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