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