]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
Eliminate dependency on man2html.
[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 void output_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, _("\nRunning 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    sendit(_("====\n"), 5, arg);
184
185    list_terminated_jobs(sendit, arg);
186
187    free_pool_memory(msg);
188 }
189
190 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
191 {
192    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
193    char level[10];
194    struct s_last_job *je;
195    const char *msg;
196
197    msg =  _("\nTerminated Jobs:\n");
198    sendit(msg, strlen(msg), arg);
199
200    if (last_jobs->size() == 0) {
201       sendit(_("====\n"), 5, arg);
202       return;
203    }
204    lock_last_jobs_list();
205    msg =  _(" JobId  Level    Files      Bytes   Status   Finished        Name \n");
206    sendit(msg, strlen(msg), arg);
207    msg = _("======================================================================\n");
208    sendit(msg, strlen(msg), arg);
209    foreach_dlist(je, last_jobs) {
210       char JobName[MAX_NAME_LENGTH];
211       const char *termstat;
212       char buf[1000];
213
214       bstrftime_nc(dt, sizeof(dt), je->end_time);
215       switch (je->JobType) {
216       case JT_ADMIN:
217       case JT_RESTORE:
218          bstrncpy(level, "    ", sizeof(level));
219          break;
220       default:
221          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
222          level[4] = 0;
223          break;
224       }
225       switch (je->JobStatus) {
226       case JS_Created:
227          termstat = _("Created");
228          break;
229       case JS_FatalError:
230       case JS_ErrorTerminated:
231          termstat = _("Error");
232          break;
233       case JS_Differences:
234          termstat = _("Diffs");
235          break;
236       case JS_Canceled:
237          termstat = _("Cancel");
238          break;
239       case JS_Terminated:
240          termstat = _("OK");
241          break;
242       default:
243          termstat = _("Other");
244          break;
245       }
246       bstrncpy(JobName, je->Job, sizeof(JobName));
247       /* There are three periods after the Job name */
248       char *p;
249       for (int i=0; i<3; i++) {
250          if ((p=strrchr(JobName, '.')) != NULL) {
251             *p = 0;
252          }
253       }
254       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %10s  %-7s  %-8s %s\n"),
255          je->JobId,
256          level,
257          edit_uint64_with_commas(je->JobFiles, b1),
258          edit_uint64_with_suffix(je->JobBytes, b2),
259          termstat,
260          dt, JobName);
261       sendit(buf, strlen(buf), arg);
262    }
263    sendit(_("====\n"), 5, arg);
264    unlock_last_jobs_list();
265 }
266
267
268 /*
269  * Send to bsock (Director or Console)
270  */
271 static void bsock_sendit(const char *msg, int len, void *arg)
272 {
273    BSOCK *user = (BSOCK *)arg;
274
275    user->msg = check_pool_memory_size(user->msg, len+1);
276    memcpy(user->msg, msg, len+1);
277    user->msglen = len+1;
278    bnet_send(user);
279 }
280
281 /*
282  * Status command from Director
283  */
284 int status_cmd(JCR *jcr)
285 {
286    BSOCK *user = jcr->dir_bsock;
287
288    bnet_fsend(user, "\n");
289    output_status(bsock_sendit, (void *)user);
290
291    bnet_sig(user, BNET_EOD);
292    return 1;
293 }
294
295 /*
296  * .status command from Director
297  */
298 int qstatus_cmd(JCR *jcr)
299 {
300    BSOCK *dir = jcr->dir_bsock;
301    POOLMEM *time;
302    JCR *njcr;
303    s_last_job* job;
304
305    time = get_memory(dir->msglen+1);
306
307    if (sscanf(dir->msg, qstatus, time) != 1) {
308       pm_strcpy(&jcr->errmsg, dir->msg);
309       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
310       bnet_fsend(dir, _("2900 Bad .status command, missing argument.\n"));
311       bnet_sig(dir, BNET_EOD);
312       free_memory(time);
313       return 0;
314    }
315    unbash_spaces(time);
316
317    if (strcmp(time, "current") == 0) {
318       bnet_fsend(dir, OKqstatus, time);
319       foreach_jcr(njcr) {
320          if (njcr->JobId != 0) {
321             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
322          }
323       }
324       endeach_jcr(njcr);
325    } else if (strcmp(time, "last") == 0) {
326       bnet_fsend(dir, OKqstatus, time);
327       if ((last_jobs) && (last_jobs->size() > 0)) {
328          job = (s_last_job*)last_jobs->last();
329          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
330       }
331    } else {
332       pm_strcpy(&jcr->errmsg, dir->msg);
333       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
334       bnet_fsend(dir, _("2900 Bad .status command, wrong argument.\n"));
335       bnet_sig(dir, BNET_EOD);
336       free_memory(time);
337       return 0;
338    }
339
340    bnet_sig(dir, BNET_EOD);
341    free_memory(time);
342    return 1;
343 }
344
345 /*
346  * Convert Job Level into a string
347  */
348 static const char *level_to_str(int level)
349 {
350    const char *str;
351
352    switch (level) {
353    case L_BASE:
354       str = _("Base");
355    case L_FULL:
356       str = _("Full");
357       break;
358    case L_INCREMENTAL:
359       str = _("Incremental");
360       break;
361    case L_DIFFERENTIAL:
362       str = _("Differential");
363       break;
364    case L_SINCE:
365       str = _("Since");
366       break;
367    case L_VERIFY_CATALOG:
368       str = _("Verify Catalog");
369       break;
370    case L_VERIFY_INIT:
371       str = _("Init Catalog");
372       break;
373    case L_VERIFY_VOLUME_TO_CATALOG:
374       str = _("Volume to Catalog");
375       break;
376    case L_VERIFY_DISK_TO_CATALOG:
377       str = _("Disk to Catalog");
378       break;
379    case L_VERIFY_DATA:
380       str = _("Data");
381       break;
382    case L_NONE:
383       str = " ";
384       break;
385    default:
386       str = _("Unknown Job Level");
387       break;
388    }
389    return str;
390 }
391
392
393 #if defined(HAVE_WIN32)
394 int bacstat = 0;
395
396 /*
397  * Put message in Window List Box
398  */
399 char *bac_status(char *buf, int buf_len)
400 {
401    JCR *njcr;
402    const char *termstat = _("Bacula Client: Idle");
403    struct s_last_job *job;
404    int stat = 0;                      /* Idle */
405
406    if (!last_jobs) {
407       goto done;
408    }
409    Dmsg0(1000, "Begin bac_status jcr loop.\n");
410    foreach_jcr(njcr) {
411       if (njcr->JobId != 0) {
412          stat = JS_Running;
413          termstat = _("Bacula Client: Running");
414          break;
415       }
416    }
417    endeach_jcr(njcr);
418
419    if (stat != 0) {
420       goto done;
421    }
422    if (last_jobs->size() > 0) {
423       job = (struct s_last_job *)last_jobs->last();
424       stat = job->JobStatus;
425       switch (job->JobStatus) {
426       case JS_Canceled:
427          termstat = _("Bacula Client: Last Job Canceled");
428          break;
429       case JS_ErrorTerminated:
430       case JS_FatalError:
431          termstat = _("Bacula Client: Last Job Failed");
432          break;
433       default:
434          if (job->Errors) {
435             termstat = _("Bacula Client: Last Job had Warnings");
436          }
437          break;
438       }
439    }
440    Dmsg0(1000, "End bac_status jcr loop.\n");
441 done:
442    bacstat = stat;
443    if (buf) {
444       bstrncpy(buf, termstat, buf_len);
445    }
446    return buf;
447 }
448
449 #endif /* HAVE_WIN32 */