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