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