]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
Apply Preben 'Peppe' Guldberg <peppe@wielders.org>
[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) 2000-2004 Kern Sibbald and John Walker
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 as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
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 GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 #include "bacula.h"
30 #include "filed.h"
31
32 extern char my_name[];
33 extern int num_jobs_run;
34 extern time_t daemon_start_time;
35 extern bool get_trace(void);
36
37 /* Forward referenced functions */
38 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg);
39 static void bsock_sendit(const char *msg, int len, void *arg);
40 static const char *level_to_str(int level);
41
42 /* Static variables */
43 static char qstatus[] = ".status %s\n";
44
45 static char OKqstatus[]   = "2000 OK .status\n";
46 static char DotStatusJob[] = "JobId=%d JobStatus=%c JobErrors=%d\n";
47
48 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
49 static int privs = 0;
50 #endif
51
52 /*
53  * General status generator
54  */
55 static void do_status(void sendit(const char *msg, int len, void *sarg), void *arg)
56 {
57    int sec, bps;
58    char *msg, b1[32], b2[32], b3[32], b4[32];
59    int found, len;
60    JCR *njcr;
61    char dt[MAX_TIME_LENGTH];
62
63    msg = (char *)get_pool_memory(PM_MESSAGE);
64    found = 0;
65    len = Mmsg(msg, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
66               HOST_OS, DISTNAME, DISTVER);
67    sendit(msg, len, arg);
68    bstrftime_nc(dt, sizeof(dt), daemon_start_time);
69    len = Mmsg(msg, _("Daemon started %s, %d Job%s run since started.\n"),
70         dt, num_jobs_run, num_jobs_run == 1 ? "" : "s");
71    sendit(msg, len, arg);
72 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
73    if (debug_level > 0) {
74       if (!privs) {
75          privs = enable_backup_privileges(NULL, 1);
76       }
77       len = Mmsg(msg,
78          _(" Priv 0x%x APIs=%sOPT,%sATP,%sLPV,%sGFAE,%sBR,%sBW,%sSPSP\n"), privs,
79          p_OpenProcessToken?"":"!",
80          p_AdjustTokenPrivileges?"":"!",
81          p_LookupPrivilegeValue?"":"!",
82          p_GetFileAttributesEx?"":"!",
83          p_BackupRead?"":"!",
84          p_BackupWrite?"":"!",
85          p_SetProcessShutdownParameters?"":"!");
86       sendit(msg, len, arg);
87    }
88 #endif
89    if (debug_level > 0) {
90       len = Mmsg(msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
91             edit_uint64_with_commas(sm_bytes, b1),
92             edit_uint64_with_commas(sm_max_bytes, b2),
93             edit_uint64_with_commas(sm_buffers, b3),
94             edit_uint64_with_commas(sm_max_buffers, b4));
95       sendit(msg, len, arg);
96       len = Mmsg(msg, _(" Sizeof: off_t=%d size_t=%d debug=%d trace=%d\n"),
97             sizeof(off_t), sizeof(size_t), debug_level, get_trace());
98       sendit(msg, len, arg);
99    }
100
101    list_terminated_jobs(sendit, arg);
102
103    /*
104     * List running jobs
105     */
106    Dmsg0(1000, "Begin status jcr loop.\n");
107    len = Mmsg(msg, _("Running Jobs:\n"));
108    sendit(msg, len, arg);
109    lock_jcr_chain();
110    foreach_jcr(njcr) {
111       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
112       if (njcr->JobId == 0) {
113          len = Mmsg(msg, _("Director connected at: %s\n"), dt);
114       } else {
115          len = Mmsg(msg, _("JobId %d Job %s is running.\n"),
116                     njcr->JobId, njcr->Job);
117          sendit(msg, len, arg);
118          len = Mmsg(msg, _("    %s Job started: %s\n"),
119                     job_type_to_str(njcr->JobType), dt);
120       }
121       sendit(msg, len, arg);
122       if (njcr->JobId == 0) {
123          free_locked_jcr(njcr);
124          continue;
125       }
126       sec = time(NULL) - njcr->start_time;
127       if (sec <= 0) {
128          sec = 1;
129       }
130       bps = (int)(njcr->JobBytes / sec);
131       len = Mmsg(msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"),
132            edit_uint64_with_commas(njcr->JobFiles, b1),
133            edit_uint64_with_commas(njcr->JobBytes, b2),
134            edit_uint64_with_commas(bps, b3));
135       sendit(msg, len, arg);
136       len = Mmsg(msg, _("    Files Examined=%s\n"),
137            edit_uint64_with_commas(njcr->num_files_examined, b1));
138       sendit(msg, len, arg);
139       if (njcr->JobFiles > 0) {
140          P(njcr->mutex);
141          len = Mmsg(msg, _("    Processing file: %s\n"), njcr->last_fname);
142          V(njcr->mutex);
143          sendit(msg, len, arg);
144       }
145
146       found = 1;
147       if (njcr->store_bsock) {
148          len = Mmsg(msg, "    SDReadSeqNo=%" lld " fd=%d\n",
149              njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
150          sendit(msg, len, arg);
151       } else {
152          len = Mmsg(msg, _("    SDSocket closed.\n"));
153          sendit(msg, len, arg);
154       }
155       free_locked_jcr(njcr);
156    }
157    unlock_jcr_chain();
158    Dmsg0(1000, "Begin status jcr loop.\n");
159    if (!found) {
160       len = Mmsg(msg, _("No Jobs running.\n"));
161       sendit(msg, len, arg);
162    }
163    len = Mmsg(msg, _("====\n"));
164    sendit(msg, len, arg);
165    free_pool_memory(msg);
166 }
167
168 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg)
169 {
170    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
171    char level[10];
172    struct s_last_job *je;
173    const char *msg;
174
175    if (last_jobs->size() == 0) {
176       msg = _("No Terminated Jobs.\n");
177       sendit(msg, strlen(msg), arg);
178       return;
179    }
180    lock_last_jobs_list();
181    sendit("\n", 1, arg);               /* send separately */
182    msg =  _("Terminated Jobs:\n");
183    sendit(msg, strlen(msg), arg);
184    msg =  _(" JobId  Level     Files         Bytes  Status   Finished        Name \n");
185    sendit(msg, strlen(msg), arg);
186    msg = _("======================================================================\n");
187    sendit(msg, strlen(msg), arg);
188    foreach_dlist(je, last_jobs) {
189       char JobName[MAX_NAME_LENGTH];
190       const char *termstat;
191       char buf[1000];
192
193       bstrftime_nc(dt, sizeof(dt), je->end_time);
194       switch (je->JobType) {
195       case JT_ADMIN:
196       case JT_RESTORE:
197          bstrncpy(level, "    ", sizeof(level));
198          break;
199       default:
200          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
201          level[4] = 0;
202          break;
203       }
204       switch (je->JobStatus) {
205       case JS_Created:
206          termstat = "Created";
207          break;
208       case JS_FatalError:
209       case JS_ErrorTerminated:
210          termstat = "Error";
211          break;
212       case JS_Differences:
213          termstat = "Diffs";
214          break;
215       case JS_Canceled:
216          termstat = "Cancel";
217          break;
218       case JS_Terminated:
219          termstat = "OK";
220          break;
221       default:
222          termstat = "Other";
223          break;
224       }
225       bstrncpy(JobName, je->Job, sizeof(JobName));
226       /* There are three periods after the Job name */
227       char *p;
228       for (int i=0; i<3; i++) {
229          if ((p=strrchr(JobName, '.')) != NULL) {
230             *p = 0;
231          }
232       }
233       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %14s %-7s  %-8s %s\n"),
234          je->JobId,
235          level,
236          edit_uint64_with_commas(je->JobFiles, b1),
237          edit_uint64_with_commas(je->JobBytes, b2),
238          termstat,
239          dt, JobName);
240       sendit(buf, strlen(buf), arg);
241    }
242    sendit("====\n", 5, arg);
243    unlock_last_jobs_list();
244 }
245
246
247 /*
248  * Send to bsock (Director or Console)
249  */
250 static void bsock_sendit(const char *msg, int len, void *arg)
251 {
252    BSOCK *user = (BSOCK *)arg;
253
254    user->msg = check_pool_memory_size(user->msg, len+1);
255    memcpy(user->msg, msg, len+1);
256    user->msglen = len+1;
257    bnet_send(user);
258 }
259
260 /*
261  * Status command from Director
262  */
263 int status_cmd(JCR *jcr)
264 {
265    BSOCK *user = jcr->dir_bsock;
266
267    bnet_fsend(user, "\n");
268    do_status(bsock_sendit, (void *)user);
269
270    bnet_sig(user, BNET_EOD);
271    return 1;
272 }
273
274 /*
275  * .status command from Director
276  */
277 int qstatus_cmd(JCR *jcr)
278 {
279    BSOCK *dir = jcr->dir_bsock;
280    POOLMEM *time;
281    JCR *njcr;
282    s_last_job* job;
283
284    time = get_memory(dir->msglen+1);
285
286    if (sscanf(dir->msg, qstatus, time) != 1) {
287       pm_strcpy(&jcr->errmsg, dir->msg);
288       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
289       bnet_fsend(dir, "2900 Bad .status command, missing argument.\n");
290       bnet_sig(dir, BNET_EOD);
291       free_memory(time);
292       return 0;
293    }
294    unbash_spaces(time);
295
296    if (strcmp(time, "current") == 0) {
297       bnet_fsend(dir, OKqstatus, time);
298       lock_jcr_chain();
299       foreach_jcr(njcr) {
300          if (njcr->JobId != 0) {
301             bnet_fsend(dir, DotStatusJob, njcr->JobId, njcr->JobStatus, njcr->JobErrors);
302          }
303          free_locked_jcr(njcr);
304       }
305       unlock_jcr_chain();
306    }
307    else if (strcmp(time, "last") == 0) {
308       bnet_fsend(dir, OKqstatus, time);
309       if ((last_jobs) && (last_jobs->size() > 0)) {
310          job = (s_last_job*)last_jobs->last();
311          bnet_fsend(dir, DotStatusJob, job->JobId, job->JobStatus, job->Errors);
312       }
313    }
314    else {
315       pm_strcpy(&jcr->errmsg, dir->msg);
316       Jmsg1(jcr, M_FATAL, 0, _("Bad .status command: %s\n"), jcr->errmsg);
317       bnet_fsend(dir, "2900 Bad .status command, wrong argument.\n");
318       bnet_sig(dir, BNET_EOD);
319       free_memory(time);
320       return 0;
321    }
322
323    bnet_sig(dir, BNET_EOD);
324    free_memory(time);
325    return 1;
326 }
327
328 /*
329  * Convert Job Level into a string
330  */
331 static const char *level_to_str(int level)
332 {
333    const char *str;
334
335    switch (level) {
336    case L_BASE:
337       str = _("Base");
338    case L_FULL:
339       str = _("Full");
340       break;
341    case L_INCREMENTAL:
342       str = _("Incremental");
343       break;
344    case L_DIFFERENTIAL:
345       str = _("Differential");
346       break;
347    case L_SINCE:
348       str = _("Since");
349       break;
350    case L_VERIFY_CATALOG:
351       str = _("Verify Catalog");
352       break;
353    case L_VERIFY_INIT:
354       str = _("Init Catalog");
355       break;
356    case L_VERIFY_VOLUME_TO_CATALOG:
357       str = _("Volume to Catalog");
358       break;
359    case L_VERIFY_DISK_TO_CATALOG:
360       str = _("Disk to Catalog");
361       break;
362    case L_VERIFY_DATA:
363       str = _("Data");
364       break;
365    case L_NONE:
366       str = " ";
367       break;
368    default:
369       str = _("Unknown Job Level");
370       break;
371    }
372    return str;
373 }
374
375
376 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
377 #include <windows.h>
378
379 int bacstat = 0;
380
381 struct s_win32_arg {
382    HWND hwnd;
383    int idlist;
384 };
385
386 /*
387  * Put message in Window List Box
388  */
389 static void win32_sendit(const char *msg, int len, void *marg)
390 {
391    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
392
393    if (len > 0 && msg[len-1] == '\n') {
394        // when compiling with visual studio some strings are read-only
395        // and cause access violations.  So we creat a tmp copy.
396        char *_msg = (char *)alloca(len);
397        bstrncpy(_msg, msg, len);
398        msg = _msg;
399    }
400    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
401
402 }
403
404 void FillStatusBox(HWND hwnd, int idlist)
405 {
406    struct s_win32_arg arg;
407
408    arg.hwnd = hwnd;
409    arg.idlist = idlist;
410
411    /* Empty box */
412    for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
413       { }
414    do_status(win32_sendit, (void *)&arg);
415 }
416
417 char *bac_status(char *buf, int buf_len)
418 {
419    JCR *njcr;
420    const char *termstat = _("Bacula Idle");
421    struct s_last_job *job;
422    int stat = 0;                      /* Idle */
423
424    if (!last_jobs) {
425       goto done;
426    }
427    Dmsg0(1000, "Begin bac_status jcr loop.\n");
428    lock_jcr_chain();
429    foreach_jcr(njcr) {
430       if (njcr->JobId != 0) {
431          stat = JS_Running;
432          termstat = _("Bacula Running");
433          free_locked_jcr(njcr);
434          break;
435       }
436       free_locked_jcr(njcr);
437    }
438    unlock_jcr_chain();
439    if (stat != 0) {
440       goto done;
441    }
442    if (last_jobs->size() > 0) {
443       job = (struct s_last_job *)last_jobs->last();
444       stat = job->JobStatus;
445       switch (job->JobStatus) {
446       case JS_Canceled:
447          termstat = _("Last Job Canceled");
448          break;
449       case JS_ErrorTerminated:
450       case JS_FatalError:
451          termstat = _("Last Job Failed");
452          break;
453       default:
454          if (job->Errors) {
455             termstat = _("Last Job had Warnings");
456          }
457          break;
458       }
459    }
460    Dmsg0(1000, "End bac_status jcr loop.\n");
461 done:
462    bacstat = stat;
463    if (buf) {
464       bstrncpy(buf, termstat, buf_len);
465    }
466    return buf;
467 }
468
469 #endif /* HAVE_CYGWIN */