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