]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
Backport from BEE
[bacula/bacula] / bacula / src / filed / status.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *  Bacula File Daemon Status routines
18  *
19  *    Kern Sibbald, August MMI
20  *
21  */
22
23 #include "bacula.h"
24 #include "filed.h"
25 #include "lib/status.h"
26
27 extern void *start_heap;
28
29 extern bool GetWindowsVersionString(char *buf, int maxsiz);
30
31
32 /* Forward referenced functions */
33 static void  list_running_jobs(STATUS_PKT *sp);
34 static void  list_status_header(STATUS_PKT *sp);
35
36 /* Static variables */
37 static char qstatus1[] = ".status %127s\n";
38 static char qstatus2[] = ".status %127s api=%d api_opts=%127s";
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_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 void output_status(STATUS_PKT *sp)
58 {
59    list_status_header(sp);
60    list_running_jobs(sp);
61    list_terminated_jobs(sp);    /* defined in lib/status.h */
62 }
63
64 #if defined(HAVE_LZO)
65 static const bool have_lzo = true;
66 #else
67 static const bool have_lzo = false;
68 #endif
69
70 static void  list_status_header(STATUS_PKT *sp)
71 {
72    POOL_MEM msg(PM_MESSAGE);
73    char b1[32], b2[32], b3[32], b4[32], b5[35];
74    int len;
75    char dt[MAX_TIME_LENGTH];
76
77    len = Mmsg(msg, _("%s Version: %s (%s) %s %s %s %s\n"),
78               my_name, VERSION, BDATE, VSS, HOST_OS,
79               DISTNAME, DISTVER);
80    sendit(msg.c_str(), len, sp);
81    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
82    len = Mmsg(msg, _("Daemon started %s. Jobs: run=%d running=%d.\n"),
83         dt, num_jobs_run, job_count());
84    sendit(msg.c_str(), len, sp);
85 #if defined(HAVE_WIN32)
86    char buf[300];
87    if (GetWindowsVersionString(buf, sizeof(buf))) {
88       len = Mmsg(msg, "%s\n", buf);
89       sendit(msg.c_str(), len, sp);
90    }
91    if (debug_level > 0) {
92       if (!privs) {
93          privs = enable_backup_privileges(NULL, 1);
94       }
95       len = Mmsg(msg, "VSS %s, Priv 0x%x\n", g_pVSSClient?"enabled":"disabled", privs);
96       sendit(msg.c_str(), len, sp);
97       len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
98                  p_OpenProcessToken?"":"!",
99                  p_AdjustTokenPrivileges?"":"!",
100                  p_LookupPrivilegeValue?"":"!",
101                  p_CreateFileA?"":"!",
102                  p_CreateFileW?"":"!");
103       sendit(msg.c_str(), len, sp);
104       len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
105                  p_wunlink?"":"!",
106                  p_wmkdir?"":"!",
107                  p_GetFileAttributesA?"":"!",
108                  p_GetFileAttributesW?"":"!",
109                  p_GetFileAttributesExA?"":"!",
110                  p_GetFileAttributesExW?"":"!",
111                  p_SetFileAttributesA?"":"!",
112                  p_SetFileAttributesW?"":"!",
113                  p_BackupRead?"":"!",
114                  p_BackupWrite?"":"!",
115                  p_SetProcessShutdownParameters?"":"!");
116       sendit(msg.c_str(), len, sp);
117       len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
118                  p_WideCharToMultiByte?"":"!",
119                  p_MultiByteToWideChar?"":"!",
120                  p_FindFirstFileA?"":"!",
121                  p_FindFirstFileW?"":"!",
122                  p_FindNextFileA?"":"!",
123                  p_FindNextFileW?"":"!",
124                  p_SetCurrentDirectoryA?"":"!",
125                  p_SetCurrentDirectoryW?"":"!");
126       sendit(msg.c_str(), len, sp);
127       len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW,%sLZO\n",
128                  p_GetCurrentDirectoryA?"":"!",
129                  p_GetCurrentDirectoryW?"":"!",
130                  p_GetVolumePathNameW?"":"!",
131                  p_GetVolumeNameForVolumeMountPointW?"":"!",
132                  have_lzo?"":"!");
133       sendit(msg.c_str(), len, sp);
134    }
135 #endif
136    len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
137          edit_uint64_with_commas((char *)sbrk(0)-(char *)start_heap, b1),
138          edit_uint64_with_commas(sm_bytes, b2),
139          edit_uint64_with_commas(sm_max_bytes, b3),
140          edit_uint64_with_commas(sm_buffers, b4),
141          edit_uint64_with_commas(sm_max_buffers, b5));
142    sendit(msg.c_str(), len, sp);
143    len = Mmsg(msg, _(" Sizes: boffset_t=%d size_t=%d debug=%s trace=%d "
144                      "mode=%d,%d bwlimit=%skB/s\n"),
145               sizeof(boffset_t), sizeof(size_t),
146               edit_uint64(debug_level, b2), get_trace(), (int)DEVELOPER_MODE, (int)BEEF,
147               edit_uint64_with_commas(me->max_bandwidth_per_job/1024, b1));
148    sendit(msg.c_str(), len, sp);
149    if (bplugin_list->size() > 0) {
150       Plugin *plugin;
151       int len;
152       pm_strcpy(msg, " Plugin: ");
153       foreach_alist(plugin, bplugin_list) {
154          len = pm_strcat(msg, plugin->file);
155          /* Print plugin version when debug activated */
156          if (debug_level > 0 && plugin->pinfo) {
157             pInfo *info = (pInfo *)plugin->pinfo;
158             pm_strcat(msg, "(");
159             pm_strcat(msg, NPRT(info->plugin_version));
160             len = pm_strcat(msg, ")");
161          }
162          if (len > 80) {
163             pm_strcat(msg, "\n   ");
164          } else {
165             pm_strcat(msg, " ");
166          }
167       }
168       len = pm_strcat(msg, "\n");
169       sendit(msg.c_str(), len, sp);
170    }
171 }
172
173 /*
174  * List running jobs in for humans.
175  */
176 static void  list_running_jobs_plain(STATUS_PKT *sp)
177 {
178    int total_sec, inst_sec, total_bps, inst_bps;
179    POOL_MEM msg(PM_MESSAGE);
180    char b1[50], b2[50], b3[50], b4[50], b5[50];
181    int len;
182    bool found = false;
183    JCR *njcr;
184    time_t now = time(NULL);
185    char dt[MAX_TIME_LENGTH];
186
187    Dmsg0(1000, "Begin status jcr loop.\n");
188    len = Mmsg(msg, _("\nRunning Jobs:\n"));
189    sendit(msg.c_str(), len, sp);
190    const char *vss = "";
191 #ifdef WIN32_VSS
192    if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
193       vss = "VSS ";
194    }
195 #endif
196    foreach_jcr(njcr) {
197       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
198       if (njcr->JobId == 0) {
199          len = Mmsg(msg, _("Director connected at: %s\n"), dt);
200       } else {
201          len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
202                     njcr->JobId, njcr->Job);
203          sendit(msg.c_str(), len, sp);
204          len = Mmsg(msg, _("    %s%s %s Job started: %s\n"),
205                     vss, job_level_to_str(njcr->getJobLevel()),
206                     job_type_to_str(njcr->getJobType()), dt);
207       }
208       sendit(msg.c_str(), len, sp);
209       if (njcr->JobId == 0) {
210          continue;
211       }
212       if (njcr->last_time == 0) {
213          njcr->last_time = njcr->start_time;
214       }
215       total_sec = now - njcr->start_time;
216       inst_sec = now - njcr->last_time;
217       if (total_sec <= 0) {
218          total_sec = 1;
219       }
220       if (inst_sec <= 0) {
221          inst_sec = 1;
222       }
223       /* Instanteous bps not smoothed */
224       inst_bps = (njcr->JobBytes - njcr->LastJobBytes) / inst_sec;
225       if (njcr->LastRate <= 0) {
226          njcr->LastRate = inst_bps;
227       }
228       /* Smooth the instantaneous bps a bit */
229       inst_bps = (2 * njcr->LastRate + inst_bps) / 3;
230       /* total bps (AveBytes/sec) since start of job */
231       total_bps = njcr->JobBytes / total_sec;
232       len = Mmsg(msg,  _("    Files=%s Bytes=%s AveBytes/sec=%s LastBytes/sec=%s Errors=%d\n"
233                          "    Bwlimit=%s\n"),
234            edit_uint64_with_commas(njcr->JobFiles, b1),
235            edit_uint64_with_commas(njcr->JobBytes, b2),
236            edit_uint64_with_commas(total_bps, b3),
237            edit_uint64_with_commas(inst_bps, b4),
238            njcr->JobErrors, edit_uint64_with_commas(njcr->max_bandwidth, b5));
239       sendit(msg.c_str(), len, sp);
240
241       if (njcr->is_JobType(JT_RESTORE) && njcr->ExpectedFiles > 0) {
242          len = Mmsg(msg, _("    Files: Restored=%s Expected=%s Completed=%d%%\n"),
243             edit_uint64_with_commas(njcr->num_files_examined, b1),
244             edit_uint64_with_commas(njcr->ExpectedFiles, b2),
245             (100*njcr->num_files_examined)/njcr->ExpectedFiles);
246       } else {
247          len = Mmsg(msg, _("    Files: Examined=%s Backed up=%s\n"),
248             edit_uint64_with_commas(njcr->num_files_examined, b1),
249             edit_uint64_with_commas(njcr->JobFiles, b2));
250       }
251       /* Update only every 10 seconds */
252       if (now - njcr->last_time > 10) {
253          njcr->LastRate = inst_bps;
254          njcr->LastJobBytes = njcr->JobBytes;
255          njcr->last_time = now;
256       }
257       sendit(msg.c_str(), len, sp);
258       if (njcr->JobFiles > 0) {
259          njcr->lock();
260          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
261          njcr->unlock();
262          sendit(msg.c_str(), len, sp);
263       }
264
265       found = true;
266       if (njcr->store_bsock) {
267          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
268              njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
269          sendit(msg.c_str(), len, sp);
270       } else {
271          len = Mmsg(msg, _("    SDSocket closed.\n"));
272          sendit(msg.c_str(), len, sp);
273       }
274    }
275    endeach_jcr(njcr);
276
277    if (!found) {
278       len = Mmsg(msg, _("No Jobs running.\n"));
279       sendit(msg.c_str(), len, sp);
280    }
281    sendit(_("====\n"), 5, sp);
282 }
283
284 static void  list_running_jobs_api(STATUS_PKT *sp)
285 {
286    int sec, bps;
287    POOL_MEM msg(PM_MESSAGE);
288    char b1[32], b2[32], b3[32];
289    int len;
290    JCR *njcr;
291    char dt[MAX_TIME_LENGTH];
292    /*
293     * List running jobs for Bat/Bweb (simple to parse)
294     */
295    int vss = 0;
296 #ifdef WIN32_VSS
297    if (g_pVSSClient && g_pVSSClient->IsInitialized()) {
298       vss = 1;
299    }
300 #endif
301    foreach_jcr(njcr) {
302       bstrutime(dt, sizeof(dt), njcr->start_time);
303       if (njcr->JobId == 0) {
304          len = Mmsg(msg, "DirectorConnected=%s\n", dt);
305       } else {
306          len = Mmsg(msg, "JobId=%d\n Job=%s\n",
307                     njcr->JobId, njcr->Job);
308          sendit(msg.c_str(), len, sp);
309          len = Mmsg(msg," VSS=%d\n Level=%c\n JobType=%c\n JobStarted=%s\n",
310                     vss, njcr->getJobLevel(),
311                     njcr->getJobType(), dt);
312       }
313       sendit(msg.c_str(), len, sp);
314       if (njcr->JobId == 0) {
315          continue;
316       }
317       sec = time(NULL) - njcr->start_time;
318       if (sec <= 0) {
319          sec = 1;
320       }
321       bps = (int)(njcr->JobBytes / sec);
322       len = Mmsg(msg, " Files=%s\n Bytes=%s\n Bytes/sec=%s\n Errors=%d\n",
323                  edit_uint64(njcr->JobFiles, b1),
324                  edit_uint64(njcr->JobBytes, b2),
325                  edit_uint64(bps, b3),
326                  njcr->JobErrors);
327       sendit(msg.c_str(), len, sp);
328       len = Mmsg(msg, " Files Examined=%s\n",
329            edit_uint64(njcr->num_files_examined, b1));
330       sendit(msg.c_str(), len, sp);
331       if (njcr->JobFiles > 0) {
332          njcr->lock();
333          len = Mmsg(msg, " Processing file=%s\n", njcr->last_fname);
334          njcr->unlock();
335          sendit(msg.c_str(), len, sp);
336       }
337
338       if (njcr->store_bsock) {
339          len = Mmsg(msg, " SDReadSeqNo=%" lld "\n fd=%d\n",
340              njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd);
341          sendit(msg.c_str(), len, sp);
342       } else {
343          len = Mmsg(msg, _(" SDSocket=closed\n"));
344          sendit(msg.c_str(), len, sp);
345       }
346    }
347    endeach_jcr(njcr);
348 }
349
350 static void  list_running_jobs(STATUS_PKT *sp)
351 {
352    if (sp->api) {
353       list_running_jobs_api(sp);
354    } else {
355       list_running_jobs_plain(sp);
356    }
357 }
358
359 /*
360  * Status command from Director
361  */
362 int status_cmd(JCR *jcr)
363 {
364    BSOCK *user = jcr->dir_bsock;
365    STATUS_PKT sp;
366
367    user->fsend("\n");
368    sp.bs = user;
369    sp.api = false;                         /* no API output */
370    output_status(&sp);
371
372    user->signal(BNET_EOD);
373    return 1;
374 }
375
376 /*
377  * .status command from Director
378  */
379 int qstatus_cmd(JCR *jcr)
380 {
381    BSOCK *dir = jcr->dir_bsock;
382    POOLMEM *cmd;
383    JCR *njcr;
384    s_last_job* job;
385    STATUS_PKT sp;
386
387    sp.bs = dir;
388    cmd = get_memory(dir->msglen+1);
389
390    if (sscanf(dir->msg, qstatus2, cmd, &sp.api, sp.api_opts) != 3) {
391       if (sscanf(dir->msg, qstatus1, cmd) != 1) {
392          pm_strcpy(&jcr->errmsg, dir->msg);
393          Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
394          dir->fsend(_("2900 Bad .status command, missing argument.\n"));
395          dir->signal(BNET_EOD);
396          free_memory(cmd);
397          return 0;
398       }
399    }
400    unbash_spaces(cmd);
401
402    if (strcasecmp(cmd, "current") == 0) {
403       dir->fsend(OKqstatus, cmd);
404       foreach_jcr(njcr) {
405          if (njcr->JobId != 0) {
406             dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
407          }
408       }
409       endeach_jcr(njcr);
410    } else if (strcasecmp(cmd, "last") == 0) {
411       dir->fsend(OKqstatus, cmd);
412       if ((last_jobs) && (last_jobs->size() > 0)) {
413          job = (s_last_job*)last_jobs->last();
414          dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
415       }
416    } else if (strcasecmp(cmd, "header") == 0) {
417        sp.api = true;
418        list_status_header(&sp);
419    } else if (strcasecmp(cmd, "running") == 0) {
420        sp.api = true;
421        list_running_jobs(&sp);
422    } else if (strcasecmp(cmd, "terminated") == 0) {
423        sp.api = MAX(sp.api, 1);
424        list_terminated_jobs(&sp); /* defined in lib/status.h */
425    } else {
426       pm_strcpy(&jcr->errmsg, dir->msg);
427       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
428       dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
429       dir->signal(BNET_EOD);
430       free_memory(cmd);
431       return 0;
432    }
433
434    dir->signal(BNET_EOD);
435    free_memory(cmd);
436    return 1;
437 }