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