]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
More minor Win32 fixes
[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-2003 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 #ifdef SMARTALLOC
36 extern uint64_t sm_max_bytes;
37 extern uint64_t sm_bytes;
38 extern uint32_t sm_max_buffers;
39 extern uint32_t sm_buffers;
40 #endif
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
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 #ifdef SMARTALLOC
90    if (debug_level > 0) {
91       len = Mmsg(&msg, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"),
92             edit_uint64_with_commas(sm_bytes, b1),
93             edit_uint64_with_commas(sm_max_bytes, b2),
94             edit_uint64_with_commas(sm_buffers, b3),
95             edit_uint64_with_commas(sm_max_buffers, b4));
96        sendit(msg, len, arg);
97     }
98 #endif
99    if (debug_level > 0) {
100       len = Mmsg(&msg, _(" Sizeof: off_t=%d size_t=%d\n"), sizeof(off_t),
101             sizeof(size_t));
102       sendit(msg, len, arg);
103    }
104
105    list_terminated_jobs(sendit, arg);
106
107    /*
108     * List running jobs  
109     */
110    Dmsg0(1000, "Begin status jcr loop.\n");
111    len = Mmsg(&msg, _("Running Jobs:\n"));
112    sendit(msg, len, arg);
113    lock_jcr_chain();
114    foreach_jcr(njcr) {
115       bstrftime_nc(dt, sizeof(dt), njcr->start_time);
116       if (njcr->JobId == 0) {
117          len = Mmsg(&msg, _("Director connected at: %s\n"), dt);
118       } else {
119          len = Mmsg(&msg, _("JobId %d Job %s is running.\n"), 
120                     njcr->JobId, njcr->Job);
121          sendit(msg, len, arg);
122          len = Mmsg(&msg, _("    %s Job started: %s\n"), 
123                     job_type_to_str(njcr->JobType), dt);
124       }
125       sendit(msg, len, arg);
126       if (njcr->JobId == 0) {
127          free_locked_jcr(njcr);
128          continue;
129       }
130       sec = time(NULL) - njcr->start_time;
131       if (sec <= 0) {
132          sec = 1;
133       }
134       bps = (int)(njcr->JobBytes / sec);
135       len = Mmsg(&msg,  _("    Files=%s Bytes=%s Bytes/sec=%s\n"), 
136            edit_uint64_with_commas(njcr->JobFiles, b1),
137            edit_uint64_with_commas(njcr->JobBytes, b2),
138            edit_uint64_with_commas(bps, b3));
139       sendit(msg, len, arg);
140       len = Mmsg(&msg, _("    Files Examined=%s\n"), 
141            edit_uint64_with_commas(njcr->num_files_examined, b1));
142       sendit(msg, len, arg);
143       if (njcr->JobFiles > 0) {
144          P(njcr->mutex);
145          len = Mmsg(&msg, _("    Processing file: %s\n"), njcr->last_fname);
146          V(njcr->mutex);
147          sendit(msg, len, arg);
148       }
149
150       found = 1;
151       if (njcr->store_bsock) {
152          len = Mmsg(&msg, "    SDReadSeqNo=%" lld " fd=%d\n",
153              njcr->store_bsock->read_seqno, njcr->store_bsock->fd);
154          sendit(msg, len, arg);
155       } else {
156          len = Mmsg(&msg, _("    SDSocket closed.\n"));
157          sendit(msg, len, arg);
158       }
159       free_locked_jcr(njcr);
160    }
161    unlock_jcr_chain();
162    Dmsg0(1000, "Begin status jcr loop.\n");
163    if (!found) {
164       len = Mmsg(&msg, _("No Jobs running.\n"));
165       sendit(msg, len, arg);
166    }
167    len = Mmsg(&msg, _("====\n"));
168    sendit(msg, len, arg);
169    free_pool_memory(msg);
170 }
171
172 static void  list_terminated_jobs(void sendit(const char *msg, int len, void *sarg), void *arg) 
173 {
174    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
175    char level[10];
176    struct s_last_job *je;
177    const char *msg;
178
179    if (last_jobs->size() == 0) {
180       msg = _("No Terminated Jobs.\n"); 
181       sendit(msg, strlen(msg), arg);
182       return;
183    }
184    lock_last_jobs_list();
185    sendit("\n", 1, arg);               /* send separately */
186    msg =  _("Terminated Jobs:\n"); 
187    sendit(msg, strlen(msg), arg);
188    msg =  _(" JobId  Level     Files         Bytes  Status   Finished        Name \n");
189    sendit(msg, strlen(msg), arg);
190    msg = _("======================================================================\n"); 
191    sendit(msg, strlen(msg), arg);
192    foreach_dlist(je, last_jobs) {
193       char JobName[MAX_NAME_LENGTH];
194       const char *termstat;
195       char buf[1000];
196
197       bstrftime_nc(dt, sizeof(dt), je->end_time);
198       switch (je->JobType) {
199       case JT_ADMIN:
200       case JT_RESTORE:
201          bstrncpy(level, "    ", sizeof(level));
202          break;
203       default:
204          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
205          level[4] = 0;
206          break;
207       }
208       switch (je->JobStatus) {
209       case JS_Created:
210          termstat = "Created";
211          break;
212       case JS_FatalError:
213       case JS_ErrorTerminated:
214          termstat = "Error";
215          break;
216       case JS_Differences:
217          termstat = "Diffs";
218          break;
219       case JS_Canceled:
220          termstat = "Cancel";
221          break;
222       case JS_Terminated:
223          termstat = "OK";
224          break;
225       default:
226          termstat = "Other";
227          break;
228       }
229       bstrncpy(JobName, je->Job, sizeof(JobName));
230       /* There are three periods after the Job name */
231       char *p;
232       for (int i=0; i<3; i++) {
233          if ((p=strrchr(JobName, '.')) != NULL) {
234             *p = 0;
235          }
236       }
237       bsnprintf(buf, sizeof(buf), _("%6d  %-6s %8s %14s %-7s  %-8s %s\n"), 
238          je->JobId,
239          level, 
240          edit_uint64_with_commas(je->JobFiles, b1),
241          edit_uint64_with_commas(je->JobBytes, b2), 
242          termstat,
243          dt, JobName);
244       sendit(buf, strlen(buf), arg);
245    }
246    sendit("====\n", 5, arg);
247    unlock_last_jobs_list();
248 }
249
250
251 /*
252  * Send to bsock (Director or Console)
253  */
254 static void bsock_sendit(const char *msg, int len, void *arg)
255 {
256    BSOCK *user = (BSOCK *)arg;
257
258    user->msg = check_pool_memory_size(user->msg, len+1);
259    memcpy(user->msg, msg, len+1);
260    user->msglen = len+1;
261    bnet_send(user);
262 }
263                                    
264 /*
265  * Status command from Director
266  */
267 int status_cmd(JCR *jcr)
268 {
269    BSOCK *user = jcr->dir_bsock;
270
271    bnet_fsend(user, "\n");
272    do_status(bsock_sendit, (void *)user);
273
274    bnet_sig(user, BNET_EOD);
275    return 1;
276 }
277
278
279 /*
280  * Convert Job Level into a string
281  */
282 static const char *level_to_str(int level) 
283 {
284    const char *str;
285
286    switch (level) {
287    case L_BASE:
288       str = _("Base");
289    case L_FULL:
290       str = _("Full");
291       break;
292    case L_INCREMENTAL:
293       str = _("Incremental");
294       break;
295    case L_DIFFERENTIAL:
296       str = _("Differential");
297       break;
298    case L_SINCE:
299       str = _("Since");
300       break;
301    case L_VERIFY_CATALOG:
302       str = _("Verify Catalog");
303       break;
304    case L_VERIFY_INIT:
305       str = _("Init Catalog");
306       break;
307    case L_VERIFY_VOLUME_TO_CATALOG:
308       str = _("Volume to Catalog");
309       break;
310    case L_VERIFY_DISK_TO_CATALOG:
311       str = _("Disk to Catalog");
312       break;
313    case L_VERIFY_DATA:
314       str = _("Data");
315       break;
316    case L_NONE:
317       str = " ";
318       break;
319    default:
320       str = _("Unknown Job Level");
321       break;
322    }
323    return str;
324 }
325
326
327 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
328 #include <windows.h>
329
330 int bacstat = 0;
331
332 struct s_win32_arg {
333    HWND hwnd;
334    int idlist;
335 };
336
337 /*
338  * Put message in Window List Box
339  */
340 static void win32_sendit(const char *msg, int len, void *marg)
341 {
342    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
343
344    if (len > 0 && msg[len-1] == '\n') {
345        // when compiling with visual studio some strings are read-only 
346        // and cause access violations.  So we creat a tmp copy.
347        char *_msg = (char *)alloca(len);
348        bstrncpy(_msg, msg, len);
349        msg = _msg;
350    }
351    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
352    
353 }
354
355 void FillStatusBox(HWND hwnd, int idlist)
356 {
357    struct s_win32_arg arg;
358
359    arg.hwnd = hwnd;
360    arg.idlist = idlist;
361
362    /* Empty box */
363    for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
364       { }
365    do_status(win32_sendit, (void *)&arg);
366 }
367
368 char *bac_status(char *buf, int buf_len)
369 {
370    JCR *njcr;
371    const char *termstat = _("Bacula Idle");
372    struct s_last_job *job;
373    int stat = 0;                      /* Idle */
374
375    if (!last_jobs) {
376       goto done;
377    }
378    Dmsg0(1000, "Begin bac_status jcr loop.\n");
379    lock_jcr_chain();
380    foreach_jcr(njcr) {
381       if (njcr->JobId != 0) {
382          stat = JS_Running;
383          termstat = _("Bacula Running");
384          free_locked_jcr(njcr);
385          break;
386       }
387       free_locked_jcr(njcr);
388    }
389    unlock_jcr_chain();
390    if (stat != 0) {
391       goto done;
392    }
393    if (last_jobs->size() > 0) {
394       job = (struct s_last_job *)last_jobs->last();
395       stat = job->JobStatus;
396       switch (job->JobStatus) {
397       case JS_Canceled:
398          termstat = _("Last Job Canceled");
399          break;
400       case JS_ErrorTerminated:
401       case JS_FatalError:  
402          termstat = _("Last Job Failed");
403          break;
404       default:
405          if (job->Errors) {
406             termstat = _("Last Job had Warnings");
407          }
408          break;
409       }
410    }
411    Dmsg0(1000, "End bac_status jcr loop.\n");
412 done:
413    bacstat = stat;
414    if (buf) {
415       bstrncpy(buf, termstat, buf_len);
416    }
417    return buf;
418 }
419
420 #endif /* HAVE_CYGWIN */