]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
kes Implement heap size display in status for all daemons.
[bacula/bacula] / bacula / src / filed / status.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Bacula File Daemon Status routines
30  *
31  *    Kern Sibbald, August MMI
32  *
33  *   Version $Id$
34  *
35  */
36
37 #include "bacula.h"
38 #include "filed.h"
39
40 extern void *start_heap;
41
42 /* Forward referenced functions */
43 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
44 static void bsock_sendit(const char *msg, int len, void *arg);
45 static const char *level_to_str(int level);
46
47 /* Static variables */
48 static char qstatus[] = ".status %s\n";
49
50 static char OKqstatus[]   = "2000 OK .status\n";
51 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
52
53 #if defined(HAVE_WIN32)
54 static int privs = 0;
55 #endif
56 #ifdef WIN32_VSS
57 #include "vss.h"
58 #define VSS " VSS"
59 extern VSSClient *g_pVSSClient;
60 #else
61 #define VSS ""
62 #endif
63
64 /*
65  * General status generator
66  */
67 void output_status(void sendit(const char *msg, int len, void *sarg), void *arg)
68 {
69    int sec, bps;
70    char *msg, b1[32], b2[32], b3[32], b4[32], b5[5];
71    int len;
72    bool found = false;
73    JCR *njcr;
74    char dt[MAX_TIME_LENGTH];
75
76    msg = (char *)get_pool_memory(PM_MESSAGE);
77    len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"), 
78               my_name, VERSION, BDATE, VSS, HOST_OS, DISTNAME, DISTVER);
79    sendit(msg, len, arg);
80    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
81    len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
82         dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
83    sendit(msg, len, arg);
84 #if defined(HAVE_WIN32)
85    if (debug_level > 0) {
86       if (!privs) {
87          privs = enable_backup_privileges(NULL, 1);
88       }
89       len = Mmsg(msg, "Priv 0x%x\n", privs);
90       sendit(msg, len, arg);
91       len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
92                  p_OpenProcessToken?"":"!",
93                  p_AdjustTokenPrivileges?"":"!",
94                  p_LookupPrivilegeValue?"":"!",
95                  p_CreateFileA?"":"!",
96                  p_CreateFileW?"":"!");
97       sendit(msg, len, arg);
98       len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
99                  p_wunlink?"":"!",
100                  p_wmkdir?"":"!",
101                  p_GetFileAttributesA?"":"!",
102                  p_GetFileAttributesW?"":"!",
103                  p_GetFileAttributesExA?"":"!",
104                  p_GetFileAttributesExW?"":"!",
105                  p_SetFileAttributesA?"":"!",
106                  p_SetFileAttributesW?"":"!",
107                  p_BackupRead?"":"!",
108                  p_BackupWrite?"":"!",
109                  p_SetProcessShutdownParameters?"":"!");
110       sendit(msg, len, arg);
111       len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
112                  p_WideCharToMultiByte?"":"!",
113                  p_MultiByteToWideChar?"":"!",
114                  p_FindFirstFileA?"":"!",
115                  p_FindFirstFileW?"":"!",
116                  p_FindNextFileA?"":"!",
117                  p_FindNextFileW?"":"!",
118                  p_SetCurrentDirectoryA?"":"!",
119                  p_SetCurrentDirectoryW?"":"!");
120       sendit(msg, len, arg);
121       len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW\n",  
122                  p_GetCurrentDirectoryA?"":"!",
123                  p_GetCurrentDirectoryW?"":"!",
124                  p_GetVolumePathNameW?"":"!",
125                  p_GetVolumeNameForVolumeMountPointW?"":"!");
126      sendit(msg, len, arg);
127    }
128 #endif
129    len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
130          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
131          edit_uint64_with_commas(sm_bytes, b2),
132          edit_uint64_with_commas(sm_max_bytes, b3),
133          edit_uint64_with_commas(sm_buffers, b4),
134          edit_uint64_with_commas(sm_max_buffers, b5));
135    sendit(msg, len, arg);
136    len = Mmsg(msg, _(" Sizeof: boffset_t=%d size_t=%d debug=%d trace=%d\n"),
137          sizeof(boffset_t), sizeof(size_t), debug_level, get_trace());
138    sendit(msg, len, arg);
139
140    /*
141     * List running jobs
142     */
143    Dmsg0(1000, "Begin status jcr loop.\n");
144    len = Mmsg(msg, _("\nRunning Jobs:\n"));
145    sendit(msg, len, arg);
146    char *vss = "";
147 #ifdef WIN32_VSS
148    if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
149       vss = "VSS ";
150    }
151 #endif
152    foreach_jcr(njcr) {
153       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
154       if (njcr->JobId == 0) {
155          len = Mmsg(msg, _("Director connected at: %s\n"), dt);
156       } else {
157          len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
158                     njcr->JobId, njcr->Job);
159          sendit(msg, len, arg);
160          len = Mmsg(msg, _("    %s%s Job started: %s\n"),
161                     vss, job_type_to_str(njcr->JobType), dt);
162       }
163       sendit(msg, len, arg);
164       if (njcr->JobId == 0) {
165          continue;
166       }
167       sec = time(NULL) - njcr->start_time;
168       if (sec <= 0) {
169          sec = 1;
170       }
171       bps = (int)(njcr->JobBytes / sec);
172       len = Mmsg(msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
173            edit_uint64_with_commas(njcr->JobFiles, b1),
174            edit_uint64_with_commas(njcr->JobBytes, b2),
175            edit_uint64_with_commas(bps, b3));
176       sendit(msg, len, arg);
177       len = Mmsg(msg, _("    Files Examined=%s\n"),
178            edit_uint64_with_commas(njcr->num_files_examined, b1));
179       sendit(msg, len, arg);
180       if (njcr->JobFiles > 0) {
181          njcr->lock();
182          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
183          njcr->unlock();
184          sendit(msg, len, arg);
185       }
186
187       found = true;
188       if (njcr->store_bsock) {
189          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
190              njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
191          sendit(msg, len, arg);
192       } else {
193          len = Mmsg(msg, _("    SDSocket closed.\n"));
194          sendit(msg, len, arg);
195       }
196    }
197    endeach_jcr(njcr);
198
199    if (!found) {
200       len = Mmsg(msg, _("No Jobs running.\n"));
201       sendit(msg, len, arg);
202    }
203    sendit(_("====\n"), 5, arg);
204
205    list_terminated_jobs(sendit, arg);
206
207    free_pool_memory(msg);
208 }
209
210 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
211 {
212    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
213    char level[10];
214    struct s_last_job *je;
215    const char *msg;
216
217    msg =  _("\nTerminated Jobs:\n");
218    sendit(msg, strlen(msg), arg);
219
220    if (last_jobs->size() == 0) {
221       sendit(_("====\n"), 5, arg);
222       return;
223    }
224    lock_last_jobs_list();
225    msg =  _(" JobId  Level    Files      Bytes   Status   Finished        Name \n");
226    sendit(msg, strlen(msg), arg);
227    msg = _("======================================================================\n");
228    sendit(msg, strlen(msg), arg);
229    foreach_dlist(je, last_jobs) {
230       char JobName[MAX_NAME_LENGTH];
231       const char *termstat;
232       char buf[1000];
233
234       bstrftime_nc(dt, sizeof(dt), je->end_time);
235       switch (je->JobType) {
236       case JT_ADMIN:
237       case JT_RESTORE:
238          bstrncpy(level, "    ", sizeof(level));
239          break;
240       default:
241          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
242          level[4] = 0;
243          break;
244       }
245       switch (je->JobStatus) {
246       case JS_Created:
247          termstat = _("Created");
248          break;
249       case JS_FatalError:
250       case JS_ErrorTerminated:
251          termstat = _("Error");
252          break;
253       case JS_Differences:
254          termstat = _("Diffs");
255          break;
256       case JS_Canceled:
257          termstat = _("Cancel");
258          break;
259       case JS_Terminated:
260          termstat = _("OK");
261          break;
262       default:
263          termstat = _("Other");
264          break;
265       }
266       bstrncpy(JobName, je->Job, sizeof(JobName));
267       /* There are three periods after the Job name */
268       char *p;
269       for (int i=0; i<3; i++) {
270          if ((p=strrchr(JobName, '.')) != NULL) {
271             *p = 0;
272          }
273       }
274       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %10s  %-7s  %-8s %s\n"),
275          je->JobId,
276          level,
277          edit_uint64_with_commas(je->JobFiles, b1),
278          edit_uint64_with_suffix(je->JobBytes, b2),
279          termstat,
280          dt, JobName);
281       sendit(buf, strlen(buf), arg);
282    }
283    sendit(_("====\n"), 5, arg);
284    unlock_last_jobs_list();
285 }
286
287
288 /*
289  * Send to bsock (Director or Console)
290  */
291 static void bsock_sendit(const char *msg, int len, void *arg)
292 {
293    BSOCK *user = (BSOCK *)arg;
294
295    user->msg = check_pool_memory_size(user->msg, len+1);
296    memcpy(user->msg, msg, len+1);
297    user->msglen = len+1;
298    bnet_send(user);
299 }
300
301 /*
302  * Status command from Director
303  */
304 int status_cmd(JCR *jcr)
305 {
306    BSOCK *user = jcr->dir_bsock;
307
308    bnet_fsend(user, "\n");
309    output_status(bsock_sendit, (void *)user);
310
311    bnet_sig(user, BNET_EOD);
312    return 1;
313 }
314
315 /*
316  * .status command from Director
317  */
318 int qstatus_cmd(JCR *jcr)
319 {
320    BSOCK *dir = jcr->dir_bsock;
321    POOLMEM *time;
322    JCR *njcr;
323    s_last_job* job;
324
325    time = get_memory(dir->msglen+1);
326
327    if (sscanf(dir->msg, qstatus, time) != 1) {
328       pm_strcpy(&jcr->errmsg, dir->msg);
329       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
330       bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
331       bnet_sig(dir, BNET_EOD);
332       free_memory(time);
333       return 0;
334    }
335    unbash_spaces(time);
336
337    if (strcmp(time, "current") == 0) {
338       bnet_fsend(dir, OKqstatus, time);
339       foreach_jcr(njcr) {
340          if (njcr->JobId != 0) {
341             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
342          }
343       }
344       endeach_jcr(njcr);
345    } else if (strcmp(time, "last") == 0) {
346       bnet_fsend(dir, OKqstatus, time);
347       if ((last_jobs) && (last_jobs->size() > 0)) {
348          job = (s_last_job*)last_jobs->last();
349          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
350       }
351    } else {
352       pm_strcpy(&jcr->errmsg, dir->msg);
353       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
354       bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
355       bnet_sig(dir, BNET_EOD);
356       free_memory(time);
357       return 0;
358    }
359
360    bnet_sig(dir, BNET_EOD);
361    free_memory(time);
362    return 1;
363 }
364
365 /*
366  * Convert Job Level into a string
367  */
368 static const char *level_to_str(int level)
369 {
370    const char *str;
371
372    switch (level) {
373    case L_BASE:
374       str = _("Base");
375    case L_FULL:
376       str = _("Full");
377       break;
378    case L_INCREMENTAL:
379       str = _("Incremental");
380       break;
381    case L_DIFFERENTIAL:
382       str = _("Differential");
383       break;
384    case L_SINCE:
385       str = _("Since");
386       break;
387    case L_VERIFY_CATALOG:
388       str = _("Verify Catalog");
389       break;
390    case L_VERIFY_INIT:
391       str = _("Init Catalog");
392       break;
393    case L_VERIFY_VOLUME_TO_CATALOG:
394       str = _("Volume to Catalog");
395       break;
396    case L_VERIFY_DISK_TO_CATALOG:
397       str = _("Disk to Catalog");
398       break;
399    case L_VERIFY_DATA:
400       str = _("Data");
401       break;
402    case L_NONE:
403       str = " ";
404       break;
405    default:
406       str = _("Unknown Job Level");
407       break;
408    }
409    return str;
410 }
411
412
413 #if defined(HAVE_WIN32)
414 int bacstat = 0;
415
416 /*
417  * Put message in Window List Box
418  */
419 char *bac_status(char *buf, int buf_len)
420 {
421    JCR *njcr;
422    const char *termstat = _("Bacula Client: Idle");
423    struct s_last_job *job;
424    int stat = 0;                      /* Idle */
425
426    if (!last_jobs) {
427       goto done;
428    }
429    Dmsg0(1000, "Begin bac_status jcr loop.\n");
430    foreach_jcr(njcr) {
431       if (njcr->JobId != 0) {
432          stat = JS_Running;
433          termstat = _("Bacula Client: Running");
434          break;
435       }
436    }
437    endeach_jcr(njcr);
438
439    if (stat != 0) {
440       goto done;
441    }
442    if (last_jobs->size() > 0) {
443       job = (struct s_last_job *)last_jobs->last();
444       stat = job->JobStatus;
445       switch (job->JobStatus) {
446       case JS_Canceled:
447          termstat = _("Bacula Client: Last Job Canceled");
448          break;
449       case JS_ErrorTerminated:
450       case JS_FatalError:
451          termstat = _("Bacula Client: Last Job Failed");
452          break;
453       default:
454          if (job->Errors) {
455             termstat = _("Bacula Client: Last Job had Warnings");
456          }
457          break;
458       }
459    }
460    Dmsg0(1000, "End bac_status jcr loop.\n");
461 done:
462    bacstat = stat;
463    if (buf) {
464       bstrncpy(buf, termstat, buf_len);
465    }
466    return buf;
467 }
468
469 #endif /* HAVE_WIN32 */