]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
added GetVolumePathW and GetVolumeNameForVolumeMountPointW to winapi. This allows...
[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: %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*/ 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,%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          free_jcr(njcr);
160          continue;
161       }
162       sec = time(NULL) - njcr->start_time;
163       if (sec <= 0) {
164          sec = 1;
165       }
166       bps = (int)(njcr->JobBytes / sec);
167       len = Mmsg(msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
168            edit_uint64_with_commas(njcr->JobFiles, b1),
169            edit_uint64_with_commas(njcr->JobBytes, b2),
170            edit_uint64_with_commas(bps, b3));
171       sendit(msg, len, arg);
172       len = Mmsg(msg, _("    Files Examined=%s\n"),
173            edit_uint64_with_commas(njcr->num_files_examined, b1));
174       sendit(msg, len, arg);
175       if (njcr->JobFiles > 0) {
176          P(njcr->mutex);
177          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
178          V(njcr->mutex);
179          sendit(msg, len, arg);
180       }
181
182       found = 1;
183       if (njcr->store_bsock) {
184          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
185              njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
186          sendit(msg, len, arg);
187       } else {
188          len = Mmsg(msg, _("    SDSocket closed.\n"));
189          sendit(msg, len, arg);
190       }
191       free_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          free_jcr(njcr);
338       }
339    }
340    else if (strcmp(time, "last") == 0) {
341       bnet_fsend(dir, OKqstatus, time);
342       if ((last_jobs) && (last_jobs->size() > 0)) {
343          job = (s_last_job*)last_jobs->last();
344          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
345       }
346    }
347    else {
348       pm_strcpy(&jcr->errmsg, dir->msg);
349       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
350       bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
351       bnet_sig(dir, BNET_EOD);
352       free_memory(time);
353       return 0;
354    }
355
356    bnet_sig(dir, BNET_EOD);
357    free_memory(time);
358    return 1;
359 }
360
361 /*
362  * Convert Job Level into a string
363  */
364 static const char *level_to_str(int level)
365 {
366    const char *str;
367
368    switch (level) {
369    case L_BASE:
370       str = _("Base");
371    case L_FULL:
372       str = _("Full");
373       break;
374    case L_INCREMENTAL:
375       str = _("Incremental");
376       break;
377    case L_DIFFERENTIAL:
378       str = _("Differential");
379       break;
380    case L_SINCE:
381       str = _("Since");
382       break;
383    case L_VERIFY_CATALOG:
384       str = _("Verify Catalog");
385       break;
386    case L_VERIFY_INIT:
387       str = _("Init Catalog");
388       break;
389    case L_VERIFY_VOLUME_TO_CATALOG:
390       str = _("Volume to Catalog");
391       break;
392    case L_VERIFY_DISK_TO_CATALOG:
393       str = _("Disk to Catalog");
394       break;
395    case L_VERIFY_DATA:
396       str = _("Data");
397       break;
398    case L_NONE:
399       str = " ";
400       break;
401    default:
402       str = _("Unknown Job Level");
403       break;
404    }
405    return str;
406 }
407
408
409 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
410 #include <windows.h>
411
412 int bacstat = 0;
413
414 struct s_win32_arg {
415    HWND hwnd;
416    int idlist;
417 };
418
419 /*
420  * Put message in Window List Box
421  */
422 static void win32_sendit(const char *msg, int len, void *marg)
423 {
424    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
425
426    if (len > 0 && msg[len-1] == '\n') {
427        // when compiling with visual studio some strings are read-only
428        // and cause access violations.  So we creat a tmp copy.
429        char *_msg = (char *)alloca(len);
430        bstrncpy(_msg, msg, len);
431        msg = _msg;
432    }
433    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
434
435 }
436
437 void FillStatusBox(HWND hwnd, int idlist)
438 {
439    struct s_win32_arg arg;
440
441    arg.hwnd = hwnd;
442    arg.idlist = idlist;
443
444    /* Empty box */
445    for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
446       { }
447    do_status(win32_sendit, (void *)&arg);
448 }
449
450 char *bac_status(char *buf, int buf_len)
451 {
452    JCR *njcr;
453    const char *termstat = _("Bacula Idle");
454    struct s_last_job *job;
455    int stat = 0;                      /* Idle */
456
457    if (!last_jobs) {
458       goto done;
459    }
460    Dmsg0(1000, "Begin bac_status jcr loop.\n");
461    foreach_jcr(njcr) {
462       if (njcr->JobId != 0) {
463          stat = JS_Running;
464          termstat = _("Bacula Running");
465          free_jcr(njcr);
466          break;
467       }
468       free_jcr(njcr);
469    }
470    if (stat != 0) {
471       goto done;
472    }
473    if (last_jobs->size() > 0) {
474       job = (struct s_last_job *)last_jobs->last();
475       stat = job->JobStatus;
476       switch (job->JobStatus) {
477       case JS_Canceled:
478          termstat = _("Last Job Canceled");
479          break;
480       case JS_ErrorTerminated:
481       case JS_FatalError:
482          termstat = _("Last Job Failed");
483          break;
484       default:
485          if (job->Errors) {
486             termstat = _("Last Job had Warnings");
487          }
488          break;
489       }
490    }
491    Dmsg0(1000, "End bac_status jcr loop.\n");
492 done:
493    bacstat = stat;
494    if (buf) {
495       bstrncpy(buf, termstat, buf_len);
496    }
497    return buf;
498 }
499
500 #endif /* HAVE_CYGWIN */