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