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