]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
Merge in all the low-risk changes from the Windows branch.
[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_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_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    len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
121          edit_uint64_with_commas(sm_bytes, b1),
122          edit_uint64_with_commas(sm_max_bytes, b2),
123          edit_uint64_with_commas(sm_buffers, b3),
124          edit_uint64_with_commas(sm_max_buffers, b4));
125    sendit(msg, len, arg);
126    len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
127          sizeof(off_t), sizeof(size_t), debug_level, get_trace());
128    sendit(msg, len, arg);
129
130    /*
131     * List running jobs
132     */
133    Dmsg0(1000, "Begin status jcr loop.\n");
134    len = Mmsg(msg, _("Running Jobs:\n"));
135    sendit(msg, len, arg);
136    char *vss = "";
137 #ifdef WIN32_VSS
138    if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
139       vss = "VSS ";
140    }
141 #endif
142    foreach_jcr(njcr) {
143       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
144       if (njcr->JobId == 0) {
145          len = Mmsg(msg, _("Director connected at: %s\n"), dt);
146       } else {
147          len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
148                     njcr->JobId, njcr->Job);
149          sendit(msg, len, arg);
150          len = Mmsg(msg, _("    %s%s Job started: %s\n"),
151                     vss, job_type_to_str(njcr->JobType), dt);
152       }
153       sendit(msg, len, arg);
154       if (njcr->JobId == 0) {
155          continue;
156       }
157       sec = time(NULL) - njcr->start_time;
158       if (sec <= 0) {
159          sec = 1;
160       }
161       bps = (int)(njcr->JobBytes / sec);
162       len = Mmsg(msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
163            edit_uint64_with_commas(njcr->JobFiles, b1),
164            edit_uint64_with_commas(njcr->JobBytes, b2),
165            edit_uint64_with_commas(bps, b3));
166       sendit(msg, len, arg);
167       len = Mmsg(msg, _("    Files Examined=%s\n"),
168            edit_uint64_with_commas(njcr->num_files_examined, b1));
169       sendit(msg, len, arg);
170       if (njcr->JobFiles > 0) {
171          njcr->lock();
172          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
173          njcr->unlock();
174          sendit(msg, len, arg);
175       }
176
177       found = 1;
178       if (njcr->store_bsock) {
179          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
180              njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
181          sendit(msg, len, arg);
182       } else {
183          len = Mmsg(msg, _("    SDSocket closed.\n"));
184          sendit(msg, len, arg);
185       }
186    }
187    endeach_jcr(njcr);
188
189    if (!found) {
190       len = Mmsg(msg, _("No Jobs running.\n"));
191       sendit(msg, len, arg);
192    }
193    len = Mmsg(msg, _("====\n"));
194    sendit(msg, len, arg);
195
196    list_terminated_jobs(sendit, arg);
197
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       }
336       endeach_jcr(njcr);
337    } else if (strcmp(time, "last") == 0) {
338       bnet_fsend(dir, OKqstatus, time);
339       if ((last_jobs) && (last_jobs->size() > 0)) {
340          job = (s_last_job*)last_jobs->last();
341          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
342       }
343    } else {
344       pm_strcpy(&jcr->errmsg, dir->msg);
345       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
346       bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
347       bnet_sig(dir, BNET_EOD);
348       free_memory(time);
349       return 0;
350    }
351
352    bnet_sig(dir, BNET_EOD);
353    free_memory(time);
354    return 1;
355 }
356
357 /*
358  * Convert Job Level into a string
359  */
360 static const char *level_to_str(int level)
361 {
362    const char *str;
363
364    switch (level) {
365    case L_BASE:
366       str = _("Base");
367    case L_FULL:
368       str = _("Full");
369       break;
370    case L_INCREMENTAL:
371       str = _("Incremental");
372       break;
373    case L_DIFFERENTIAL:
374       str = _("Differential");
375       break;
376    case L_SINCE:
377       str = _("Since");
378       break;
379    case L_VERIFY_CATALOG:
380       str = _("Verify Catalog");
381       break;
382    case L_VERIFY_INIT:
383       str = _("Init Catalog");
384       break;
385    case L_VERIFY_VOLUME_TO_CATALOG:
386       str = _("Volume to Catalog");
387       break;
388    case L_VERIFY_DISK_TO_CATALOG:
389       str = _("Disk to Catalog");
390       break;
391    case L_VERIFY_DATA:
392       str = _("Data");
393       break;
394    case L_NONE:
395       str = " ";
396       break;
397    default:
398       str = _("Unknown Job Level");
399       break;
400    }
401    return str;
402 }
403
404
405 #if defined(HAVE_WIN32)
406 #include <windows.h>
407
408 int bacstat = 0;
409
410 struct s_win32_arg {
411    HWND hwnd;
412    int idlist;
413 };
414
415 /*
416  * Put message in Window List Box
417  */
418 static void win32_sendit(const char *msg, int len, void *marg)
419 {
420    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
421
422    if (len > 0 && msg[len-1] == '\n') {
423        // when compiling with visual studio some strings are read-only
424        // and cause access violations.  So we creat a tmp copy.
425        char *_msg = (char *)alloca(len);
426        bstrncpy(_msg, msg, len);
427        msg = _msg;
428    }
429    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
430
431 }
432
433 void FillStatusBox(HWND hwnd, int idlist)
434 {
435    struct s_win32_arg arg;
436
437    arg.hwnd = hwnd;
438    arg.idlist = idlist;
439
440    /* Empty box */
441    for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
442       { }
443    do_status(win32_sendit, (void *)&arg);
444 }
445
446 char *bac_status(char *buf, int buf_len)
447 {
448    JCR *njcr;
449    const char *termstat = _("Bacula Idle");
450    struct s_last_job *job;
451    int stat = 0;                      /* Idle */
452
453    if (!last_jobs) {
454       goto done;
455    }
456    Dmsg0(1000, "Begin bac_status jcr loop.\n");
457    foreach_jcr(njcr) {
458       if (njcr->JobId != 0) {
459          stat = JS_Running;
460          termstat = _("Bacula Running");
461          break;
462       }
463    }
464    endeach_jcr(njcr);
465
466    if (stat != 0) {
467       goto done;
468    }
469    if (last_jobs->size() > 0) {
470       job = (struct s_last_job *)last_jobs->last();
471       stat = job->JobStatus;
472       switch (job->JobStatus) {
473       case JS_Canceled:
474          termstat = _("Last Job Canceled");
475          break;
476       case JS_ErrorTerminated:
477       case JS_FatalError:
478          termstat = _("Last Job Failed");
479          break;
480       default:
481          if (job->Errors) {
482             termstat = _("Last Job had Warnings");
483          }
484          break;
485       }
486    }
487    Dmsg0(1000, "End bac_status jcr loop.\n");
488 done:
489    bacstat = stat;
490    if (buf) {
491       bstrncpy(buf, termstat, buf_len);
492    }
493    return buf;
494 }
495
496 #endif /* HAVE_WIN32 */