]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/status.c
Eliminate zombie job in SD
[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    bnet_fsend(user, "====\n");
253
254    bnet_sig(user, BNET_EOD);
255    return 1;
256 }
257
258
259 /*
260  * Convert Job Level into a string
261  */
262 static char *level_to_str(int level) 
263 {
264    char *str;
265
266    switch (level) {
267    case L_BASE:
268       str = _("Base");
269    case L_FULL:
270       str = _("Full");
271       break;
272    case L_INCREMENTAL:
273       str = _("Incremental");
274       break;
275    case L_DIFFERENTIAL:
276       str = _("Differential");
277       break;
278    case L_SINCE:
279       str = _("Since");
280       break;
281    case L_VERIFY_CATALOG:
282       str = _("Verify Catalog");
283       break;
284    case L_VERIFY_INIT:
285       str = _("Init Catalog");
286       break;
287    case L_VERIFY_VOLUME_TO_CATALOG:
288       str = _("Volume to Catalog");
289       break;
290    case L_VERIFY_DISK_TO_CATALOG:
291       str = _("Disk to Catalog");
292       break;
293    case L_VERIFY_DATA:
294       str = _("Data");
295       break;
296    case L_NONE:
297       str = " ";
298       break;
299    default:
300       str = _("Unknown Job Level");
301       break;
302    }
303    return str;
304 }
305
306
307 #if defined(HAVE_CYGWIN) || defined(HAVE_WIN32)
308 #include <windows.h>
309
310 static char buf[100];
311 int bacstat = 0;
312
313 struct s_win32_arg {
314    HWND hwnd;
315    int idlist;
316 };
317
318 /*
319  * Put message in Window List Box
320  */
321 static void win32_sendit(const char *msg, int len, void *marg)
322 {
323    struct s_win32_arg *arg = (struct s_win32_arg *)marg;
324
325    if (len > 0 && msg[len-1] == '\n') {
326        // when compiling with visual studio some strings are read-only 
327        // and cause access violations.  So we creat a tmp copy.
328        char *_msg = (char *)alloca(len);
329        strncpy(_msg, msg, len-1);
330        _msg[len-1] = 0;
331        msg = _msg;
332    }
333    SendDlgItemMessage(arg->hwnd, arg->idlist, LB_ADDSTRING, 0, (LONG)msg);
334    
335 }
336
337 void FillStatusBox(HWND hwnd, int idlist)
338 {
339    struct s_win32_arg arg;
340
341    arg.hwnd = hwnd;
342    arg.idlist = idlist;
343
344    /* Empty box */
345    for ( ; SendDlgItemMessage(hwnd, idlist, LB_DELETESTRING, 0, (LONG)0) > 0; )
346       { }
347    do_status(win32_sendit, (void *)&arg);
348 }
349
350 char *bac_status(int stat)
351 {
352    JCR *njcr;
353    char *termstat = _("Bacula Idle");
354    struct s_last_job *job;
355
356    bacstat = 0;
357    if (last_jobs->size() > 0) {
358       job = (struct s_last_job *)last_jobs->first();
359       switch (job->JobStatus) {
360       case JS_Canceled:
361          bacstat = -1;
362          termstat = _("Last Job Canceled");
363          break;
364       case JS_ErrorTerminated:
365          bacstat = -1;
366          termstat = _("Last Job Failed");
367          break;
368       default:
369          break;
370       }
371    }
372    Dmsg0(1000, "Begin bac_status jcr loop.\n");
373    lock_jcr_chain();
374    foreach_jcr(njcr) {
375       if (njcr->JobId != 0) {
376          bacstat = 1;
377          termstat = _("Bacula Running");
378          free_locked_jcr(njcr);
379          break;
380       }
381       free_locked_jcr(njcr);
382    }
383    unlock_jcr_chain();
384    Dmsg0(1000, "End bac_status jcr loop.\n");
385    bstrncpy(buf, termstat, sizeof(buf));
386    return buf;
387 }
388
389 #endif /* HAVE_CYGWIN */