]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
Restore win32 dir from Branch-5.2 and update it
[bacula/bacula] / bacula / src / filed / status.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2018 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many 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    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Bacula File Daemon Status routines
21  *
22  *    Kern Sibbald, August MMI
23  *
24  */
25
26 #include "bacula.h"
27 #include "filed.h"
28 #include "lib/status.h"
29
30 extern void *start_heap;
31
32 extern bool GetWindowsVersionString(char *buf, int maxsiz);
33
34
35 /* Forward referenced functions */
36 static void  list_running_jobs(STATUS_PKT *sp);
37 static void  list_status_header(STATUS_PKT *sp);
38
39 /* Static variables */
40 static char qstatus1[] = ".status %127s\n";
41 static char qstatus2[] = ".status %127s api=%d api_opts=%127s";
42
43 static char OKqstatus[]   = "2000 OK .status\n";
44 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
45
46 #if defined(HAVE_WIN32)
47 static int privs = 0;
48 #endif
49 #ifdef WIN32_VSS
50 #include "vss.h"
51 #define VSS " VSS"
52 #else
53 #define VSS ""
54 #endif
55
56 /*
57  * General status generator
58  */
59 void output_status(STATUS_PKT *sp)
60 {
61    list_status_header(sp);
62    list_running_jobs(sp);
63    list_terminated_jobs(sp);    /* defined in lib/status.h */
64 }
65
66 #if defined(HAVE_LZO)
67 static const bool have_lzo = true;
68 #else
69 static const bool have_lzo = false;
70 #endif
71
72
73 static void api_list_status_header(STATUS_PKT *sp)
74 {
75    char *p;
76    char buf[300];
77    OutputWriter wt(sp->api_opts);
78    *buf = 0;
79
80 #if defined(HAVE_WIN32)
81    if (!GetWindowsVersionString(buf, sizeof(buf))) {
82       *buf = 0;
83    }
84 #endif
85
86    wt.start_group("header");
87    wt.get_output(
88       OT_STRING, "name",        my_name,
89       OT_STRING, "version",     VERSION " (" BDATE ")",
90       OT_STRING, "uname",       HOST_OS " " DISTNAME " " DISTVER,
91       OT_UTIME,  "started",     daemon_start_time,
92       OT_INT,    "jobs_run",    num_jobs_run,
93       OT_INT,    "jobs_running",job_count(),
94       OT_STRING, "winver",      buf,
95       OT_INT64,  "debug",       debug_level,
96       OT_INT,    "trace",       get_trace(),
97       OT_INT64,  "bwlimit",     me->max_bandwidth_per_job,
98       OT_PLUGINS, "plugins",    b_plugin_list,
99       OT_END);
100    p = wt.end_group();
101    sendit(p, strlen(p), sp);
102 }
103
104 static void  list_status_header(STATUS_PKT *sp)
105 {
106    POOL_MEM msg(PM_MESSAGE);
107    char b1[32], b2[32], b3[32], b4[32], b5[35];
108    int64_t memused = (char *)sbrk(0)-(char *)start_heap;
109    int len;
110    char dt[MAX_TIME_LENGTH];
111
112    if (sp->api) {
113       api_list_status_header(sp);
114       return;
115    }
116
117    len = Mmsg(msg, _("%s %sVersion: %s (%s) %s %s %s %s\n"),
118               my_name, BDEMO, VERSION, BDATE, VSS, HOST_OS,
119               DISTNAME, DISTVER);
120    sendit(msg.c_str(), len, sp);
121    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
122    len = Mmsg(msg, _("Daemon started %s. Jobs: run=%d running=%d.\n"),
123         dt, num_jobs_run, job_count());
124    sendit(msg.c_str(), len, sp);
125 #if defined(HAVE_WIN32)
126    char buf[300];
127    if (GetWindowsVersionString(buf, sizeof(buf))) {
128       len = Mmsg(msg, "%s\n", buf);
129       sendit(msg.c_str(), len, sp);
130    }
131    memused = get_memory_info(buf, sizeof(buf));
132    if (debug_level > 0) {
133       if (!privs) {
134          privs = enable_backup_privileges(NULL, 1);
135       }
136       len = Mmsg(msg, "Priv 0x%x\n", privs);
137       sendit(msg.c_str(), len, sp);
138
139       /* Display detailed information that we got from get_memory_info() */
140       len = Mmsg(msg, "Memory: %s\n", buf);
141       sendit(msg.c_str(), len, sp);
142
143       len = Mmsg(msg, "APIs=%sOPT,%sATP,%sLPV,%sCFA,%sCFW,\n",
144                  p_OpenProcessToken?"":"!",
145                  p_AdjustTokenPrivileges?"":"!",
146                  p_LookupPrivilegeValue?"":"!",
147                  p_CreateFileA?"":"!",
148                  p_CreateFileW?"":"!");
149       sendit(msg.c_str(), len, sp);
150       len = Mmsg(msg, " %sWUL,%sWMKD,%sGFAA,%sGFAW,%sGFAEA,%sGFAEW,%sSFAA,%sSFAW,%sBR,%sBW,%sSPSP,\n",
151                  p_wunlink?"":"!",
152                  p_wmkdir?"":"!",
153                  p_GetFileAttributesA?"":"!",
154                  p_GetFileAttributesW?"":"!",
155                  p_GetFileAttributesExA?"":"!",
156                  p_GetFileAttributesExW?"":"!",
157                  p_SetFileAttributesA?"":"!",
158                  p_SetFileAttributesW?"":"!",
159                  p_BackupRead?"":"!",
160                  p_BackupWrite?"":"!",
161                  p_SetProcessShutdownParameters?"":"!");
162       sendit(msg.c_str(), len, sp);
163       len = Mmsg(msg, " %sWC2MB,%sMB2WC,%sFFFA,%sFFFW,%sFNFA,%sFNFW,%sSCDA,%sSCDW,\n",
164                  p_WideCharToMultiByte?"":"!",
165                  p_MultiByteToWideChar?"":"!",
166                  p_FindFirstFileA?"":"!",
167                  p_FindFirstFileW?"":"!",
168                  p_FindNextFileA?"":"!",
169                  p_FindNextFileW?"":"!",
170                  p_SetCurrentDirectoryA?"":"!",
171                  p_SetCurrentDirectoryW?"":"!");
172       sendit(msg.c_str(), len, sp);
173       len = Mmsg(msg, " %sGCDA,%sGCDW,%sGVPNW,%sGVNFVMPW,%sLZO,%sEFS\n",
174                  p_GetCurrentDirectoryA?"":"!",
175                  p_GetCurrentDirectoryW?"":"!",
176                  p_GetVolumePathNameW?"":"!",
177                  p_GetVolumeNameForVolumeMountPointW?"":"!",
178                  have_lzo?"":"!",
179                  "!");
180       sendit(msg.c_str(), len, sp);
181    }
182 #endif
183    len = Mmsg(msg, _(" Heap: heap=%s smbytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
184          edit_uint64_with_commas(memused, b1),
185          edit_uint64_with_commas(sm_bytes, b2),
186          edit_uint64_with_commas(sm_max_bytes, b3),
187          edit_uint64_with_commas(sm_buffers, b4),
188          edit_uint64_with_commas(sm_max_buffers, b5));
189    sendit(msg.c_str(), len, sp);
190    len = Mmsg(msg, _(" Sizes: boffset_t=%d size_t=%d debug=%s trace=%d "
191                      "mode=%d,%d bwlimit=%skB/s\n"),
192               sizeof(boffset_t), sizeof(size_t),
193               edit_uint64(debug_level, b2), get_trace(), (int)DEVELOPER_MODE, 0,
194               edit_uint64_with_commas(me->max_bandwidth_per_job/1024, b1));
195    sendit(msg.c_str(), len, sp);
196    if (b_plugin_list && b_plugin_list->size() > 0) {
197       Plugin *plugin;
198       int len;
199       pm_strcpy(msg, " Plugin: ");
200       foreach_alist(plugin, b_plugin_list) {
201          len = pm_strcat(msg, plugin->file);
202          /* Print plugin version when debug activated */
203          if (debug_level > 0 && plugin->pinfo) {
204             pInfo *info = (pInfo *)plugin->pinfo;
205             pm_strcat(msg, "(");
206             pm_strcat(msg, NPRT(info->plugin_version));
207             len = pm_strcat(msg, ")");
208          }
209          if (len > 80) {
210             pm_strcat(msg, "\n   ");
211          } else {
212             pm_strcat(msg, " ");
213          }
214       }
215       len = pm_strcat(msg, "\n");
216       sendit(msg.c_str(), len, sp);
217    }
218 }
219
220 /*
221  * List running jobs in for humans.
222  */
223 static void  list_running_jobs_plain(STATUS_PKT *sp)
224 {
225    int total_sec, inst_sec;
226    uint64_t total_bps, inst_bps;
227    POOL_MEM msg(PM_MESSAGE);
228    char b1[50], b2[50], b3[50], b4[50], b5[50], b6[50];
229    int len;
230    bool found = false;
231    JCR *njcr;
232    time_t now = time(NULL);
233    char dt[MAX_TIME_LENGTH];
234
235    Dmsg0(1000, "Begin status jcr loop.\n");
236    len = Mmsg(msg, _("\nRunning Jobs:\n"));
237    sendit(msg.c_str(), len, sp);
238    foreach_jcr(njcr) {
239       const char *vss = "";
240 #ifdef WIN32_VSS
241       if (njcr->pVSSClient && njcr->pVSSClient->IsInitialized()) {
242          vss = "VSS ";
243       }
244 #endif
245       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
246       if (njcr->JobId == 0) {
247          len = Mmsg(msg, _("Director connected %sat: %s\n"),
248                     (njcr->dir_bsock && njcr->dir_bsock->tls)?_("using TLS "):"",
249                     dt);
250       } else {
251          len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
252                     njcr->JobId, njcr->Job);
253          sendit(msg.c_str(), len, sp);
254          len = Mmsg(msg, _("    %s%s %s Job started: %s\n"),
255                     vss, job_level_to_str(njcr->getJobLevel()),
256                     job_type_to_str(njcr->getJobType()), dt);
257       }
258       sendit(msg.c_str(), len, sp);
259       if (njcr->JobId == 0) {
260          continue;
261       }
262       if (njcr->last_time == 0) {
263          njcr->last_time = njcr->start_time;
264       }
265       total_sec = now - njcr->start_time;
266       inst_sec = now - njcr->last_time;
267       if (total_sec <= 0) {
268          total_sec = 1;
269       }
270       if (inst_sec <= 0) {
271          inst_sec = 1;
272       }
273       /* Instanteous bps not smoothed */
274       inst_bps = (njcr->JobBytes - njcr->LastJobBytes) / inst_sec;
275       if (njcr->LastRate <= 0) {
276          njcr->LastRate = inst_bps;
277       }
278       /* Smooth the instantaneous bps a bit */
279       inst_bps = (2 * njcr->LastRate + inst_bps) / 3;
280       /* total bps (AveBytes/sec) since start of job */
281       total_bps = njcr->JobBytes / total_sec;
282       len = Mmsg(msg,  _("    Files=%s Bytes=%s AveBytes/sec=%s LastBytes/sec=%s Errors=%d\n"
283                          "    Bwlimit=%s ReadBytes=%s\n"),
284            edit_uint64_with_commas(njcr->JobFiles, b1),
285            edit_uint64_with_commas(njcr->JobBytes, b2),
286            edit_uint64_with_commas(total_bps, b3),
287            edit_uint64_with_commas(inst_bps, b4),
288            njcr->JobErrors, edit_uint64_with_commas(njcr->max_bandwidth, b5),
289            edit_uint64_with_commas(njcr->ReadBytes, b6));
290       sendit(msg.c_str(), len, sp);
291
292       if (njcr->is_JobType(JT_RESTORE)) {
293          if (njcr->ExpectedFiles > 0) {
294             len = Mmsg(msg, _("    Files: Restored=%s Expected=%s Completed=%d%%\n"),
295                        edit_uint64_with_commas(njcr->num_files_examined, b1),
296                        edit_uint64_with_commas(njcr->ExpectedFiles, b2),
297                        (100*njcr->num_files_examined)/njcr->ExpectedFiles);
298
299          } else {
300             len = Mmsg(msg, _("    Files: Restored=%s\n"),
301                        edit_uint64_with_commas(njcr->num_files_examined, b1));
302          }
303       } else {
304          len = Mmsg(msg, _("    Files: Examined=%s Backed up=%s\n"),
305             edit_uint64_with_commas(njcr->num_files_examined, b1),
306             edit_uint64_with_commas(njcr->JobFiles, b2));
307       }
308       /* Update only every 10 seconds */
309       if (now - njcr->last_time > 10) {
310          njcr->LastRate = inst_bps;
311          njcr->LastJobBytes = njcr->JobBytes;
312          njcr->last_time = now;
313       }
314       sendit(msg.c_str(), len, sp);
315       if (njcr->JobFiles > 0) {
316          njcr->lock();
317          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
318          njcr->unlock();
319          sendit(msg.c_str(), len, sp);
320       }
321
322       found = true;
323       if (njcr->store_bsock) {
324          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d SDtls=%d\n",
325                     njcr->store_bsock->read_seqno, njcr->store_bsock->m_fd,
326                     (njcr->store_bsock->tls)?1:0);
327          sendit(msg.c_str(), len, sp);
328       } else {
329          len = Mmsg(msg, _("    SDSocket closed.\n"));
330          sendit(msg.c_str(), len, sp);
331       }
332    }
333    endeach_jcr(njcr);
334
335    if (!found) {
336       len = Mmsg(msg, _("No Jobs running.\n"));
337       sendit(msg.c_str(), len, sp);
338    }
339    sendit(_("====\n"), 5, sp);
340 }
341
342 /*
343  * List running jobs for Bat or Bweb in a format
344  *  simpler to parse. Be careful when changing this
345  *  subroutine.
346  */
347 static void  list_running_jobs_api(STATUS_PKT *sp)
348 {
349    OutputWriter ow(sp->api_opts);
350    int sec, bps;
351    char *p;
352    JCR *njcr;
353
354    /* API v1, edit with comma, space before the name, sometime ' ' as separator */
355
356    foreach_jcr(njcr) {
357       int vss = 0;
358 #ifdef WIN32_VSS
359       if (njcr->pVSSClient && njcr->pVSSClient->IsInitialized()) {
360          vss = 1;
361       }
362 #endif
363       p = ow.get_output(OT_CLEAR, OT_START_OBJ, OT_END);
364
365       if (njcr->JobId == 0) {
366          int val = (njcr->dir_bsock && njcr->dir_bsock->tls)?1:0;
367          ow.get_output(OT_UTIME, "DirectorConnected", njcr->start_time,
368                        OT_INT, "DirTLS", val,
369                        OT_END);
370       } else {
371          ow.get_output(OT_INT32,   "JobId", njcr->JobId,
372                        OT_STRING,  "Job",   njcr->Job,
373                        OT_INT,     "VSS",   vss,
374                        OT_JOBLEVEL,"Level", njcr->getJobLevel(),
375                        OT_JOBTYPE, "Type",  njcr->getJobType(),
376                        OT_JOBSTATUS, "Status", njcr->getJobStatus(),
377                        OT_UTIME,   "StartTime", njcr->start_time,
378                        OT_END);
379
380       }
381       sendit(p, strlen(p), sp);
382       if (njcr->JobId == 0) {
383          continue;
384       }
385       sec = time(NULL) - njcr->start_time;
386       if (sec <= 0) {
387          sec = 1;
388       }
389       bps = (int)(njcr->JobBytes / sec);
390       ow.get_output(OT_CLEAR,
391                     OT_INT32,   "JobFiles",  njcr->JobFiles,
392                     OT_SIZE,    "JobBytes",  njcr->JobBytes,
393                     OT_INT,     "Bytes/sec", bps,
394                     OT_INT,     "Errors",    njcr->JobErrors,
395                     OT_INT64,   "Bwlimit",   njcr->max_bandwidth,
396                     OT_SIZE,    "ReadBytes", njcr->ReadBytes,
397                     OT_END);
398
399       ow.get_output(OT_INT32,  "Files Examined",  njcr->num_files_examined, OT_END);
400
401       if (njcr->is_JobType(JT_RESTORE) && njcr->ExpectedFiles > 0) {
402          ow.get_output(OT_INT32,  "Expected Files",  njcr->ExpectedFiles,
403                        OT_INT32,  "Percent Complete", 100*(njcr->num_files_examined/njcr->ExpectedFiles),
404                        OT_END);
405       }
406
407       sendit(p, strlen(p), sp);
408       ow.get_output(OT_CLEAR, OT_END);
409
410       if (njcr->JobFiles > 0) {
411          njcr->lock();
412          ow.get_output(OT_STRING,  "Processing file", njcr->last_fname, OT_END);
413          njcr->unlock();
414       }
415
416       if (njcr->store_bsock) {
417          int val = (njcr->store_bsock->tls)?1:0;
418          ow.get_output(OT_INT64, "SDReadSeqNo", (int64_t)njcr->store_bsock->read_seqno,
419                        OT_INT,   "fd",          njcr->store_bsock->m_fd,
420                        OT_INT,   "SDtls",       val,
421                        OT_END);
422       } else {
423          ow.get_output(OT_STRING, "SDSocket", "closed", OT_END);
424       }
425       ow.get_output(OT_END_OBJ, OT_END);
426       sendit(p, strlen(p), sp);
427    }
428    endeach_jcr(njcr);
429 }
430
431 static void  list_running_jobs(STATUS_PKT *sp)
432 {
433    if (sp->api) {
434       list_running_jobs_api(sp);
435    } else {
436       list_running_jobs_plain(sp);
437    }
438 }
439
440 /*
441  * Status command from Director
442  */
443 int status_cmd(JCR *jcr)
444 {
445    BSOCK *user = jcr->dir_bsock;
446    STATUS_PKT sp;
447
448    user->fsend("\n");
449    sp.bs = user;
450    sp.api = false;                         /* no API output */
451    output_status(&sp);
452
453    user->signal(BNET_EOD);
454    return 1;
455 }
456
457 /*
458  * .status command from Director
459  */
460 int qstatus_cmd(JCR *jcr)
461 {
462    BSOCK *dir = jcr->dir_bsock;
463    POOLMEM *cmd;
464    JCR *njcr;
465    s_last_job* job;
466    STATUS_PKT sp;
467
468    sp.bs = dir;
469    cmd = get_memory(dir->msglen+1);
470
471    if (sscanf(dir->msg, qstatus2, cmd, &sp.api, sp.api_opts) != 3) {
472       if (sscanf(dir->msg, qstatus1, cmd) != 1) {
473          pm_strcpy(&jcr->errmsg, dir->msg);
474          Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
475          dir->fsend(_("2900 Bad .status command, missing argument.\n"));
476          dir->signal(BNET_EOD);
477          free_memory(cmd);
478          return 0;
479       }
480    }
481    unbash_spaces(cmd);
482
483    if (strcasecmp(cmd, "current") == 0) {
484       dir->fsend(OKqstatus, cmd);
485       foreach_jcr(njcr) {
486          if (njcr->JobId != 0) {
487             dir->fsend(DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
488          }
489       }
490       endeach_jcr(njcr);
491    } else if (strcasecmp(cmd, "last") == 0) {
492       dir->fsend(OKqstatus, cmd);
493       if ((last_jobs) && (last_jobs->size() > 0)) {
494          job = (s_last_job*)last_jobs->last();
495          dir->fsend(DotStatusJob, job->JobId, job->JobStatus, job->Errors);
496       }
497    } else if (strcasecmp(cmd, "header") == 0) {
498        sp.api = true;
499        list_status_header(&sp);
500    } else if (strcasecmp(cmd, "running") == 0) {
501        sp.api = true;
502        list_running_jobs(&sp);
503    } else if (strcasecmp(cmd, "terminated") == 0) {
504        sp.api = MAX(sp.api, 1);
505        list_terminated_jobs(&sp); /* defined in lib/status.h */
506    } else {
507       pm_strcpy(&jcr->errmsg, dir->msg);
508       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
509       dir->fsend(_("2900 Bad .status command, wrong argument.\n"));
510       dir->signal(BNET_EOD);
511       free_memory(cmd);
512       return 0;
513    }
514
515    dir->signal(BNET_EOD);
516    free_memory(cmd);
517    return 1;
518 }