]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_status.c
a01ac3806f81ec65ee886c2042c7de1edfb396df
[bacula/bacula] / bacula / src / dird / ua_status.c
1 /*
2  *
3  *   Bacula Director -- User Agent Status Command
4  *
5  *     Kern Sibbald, August MMI
6  *
7  *   Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2003 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32 #include "ua.h"
33
34 extern char my_name[];
35 extern time_t daemon_start_time;
36 extern struct s_last_job last_job;
37
38 static void print_jobs_scheduled(UAContext *ua);
39 static void do_storage_status(UAContext *ua, STORE *store);
40 static void do_client_status(UAContext *ua, CLIENT *client);
41 static void do_director_status(UAContext *ua, char *cmd);
42 static void do_all_status(UAContext *ua, char *cmd);
43
44 /*
45  * status command
46  */
47 int statuscmd(UAContext *ua, char *cmd)
48 {
49    STORE *store;
50    CLIENT *client;
51    int item, i;
52
53    if (!open_db(ua)) {
54       return 1;
55    }
56    Dmsg1(20, "status:%s:\n", cmd);
57
58    for (i=1; i<ua->argc; i++) {
59       if (strcasecmp(ua->argk[i], _("all")) == 0) {
60          do_all_status(ua, cmd);
61          return 1;
62       } else if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
63                  strcasecmp(ua->argk[i], _("director")) == 0) {
64          do_director_status(ua, cmd);
65          return 1;
66       } else if (strcasecmp(ua->argk[i], _("client")) == 0) {
67          client = get_client_resource(ua);
68          if (client) {
69             do_client_status(ua, client);
70          }
71          return 1;
72       } else {
73          store = get_storage_resource(ua, cmd);
74          if (store) {
75             do_storage_status(ua, store);
76          }
77          return 1;
78       }
79    }
80    /* If no args, ask for status type */
81    if (ua->argc == 1) {                                    
82       start_prompt(ua, _("Status available for:\n"));
83       add_prompt(ua, _("Director"));
84       add_prompt(ua, _("Storage"));
85       add_prompt(ua, _("Client"));
86       add_prompt(ua, _("All"));
87       Dmsg0(20, "do_prompt: select daemon\n");
88       if ((item=do_prompt(ua, _("Select daemon type for status"), cmd, MAX_NAME_LENGTH)) < 0) {
89          return 1;
90       }
91       Dmsg1(20, "item=%d\n", item);
92       switch (item) { 
93       case 0:                         /* Director */
94          do_director_status(ua, cmd);
95          break;
96       case 1:
97          store = select_storage_resource(ua);
98          if (store) {
99             do_storage_status(ua, store);
100          }
101          break;
102       case 2:
103          client = select_client_resource(ua);
104          if (client) {
105             do_client_status(ua, client);
106          }
107          break;
108       case 3:
109          do_all_status(ua, cmd);
110          break;
111       default:
112          break;
113       }
114    }
115    return 1;
116 }
117
118 static void do_all_status(UAContext *ua, char *cmd)
119 {
120    STORE *store, **unique_store;
121    CLIENT *client, **unique_client;
122    int i, j, found;
123
124    do_director_status(ua, cmd);
125
126    /* Count Storage items */
127    LockRes();
128    store = NULL;
129    for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
130       { }
131    unique_store = (STORE **) malloc(i * sizeof(STORE));
132    /* Find Unique Storage address/port */         
133    store = (STORE *)GetNextRes(R_STORAGE, NULL);
134    i = 0;
135    unique_store[i++] = store;
136    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
137       found = 0;
138       for (j=0; j<i; j++) {
139          if (strcmp(unique_store[j]->address, store->address) == 0 &&
140              unique_store[j]->SDport == store->SDport) {
141             found = 1;
142             break;
143          }
144       }
145       if (!found) {
146          unique_store[i++] = store;
147          Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport);
148       }
149    }
150    UnlockRes();
151
152    /* Call each unique Storage daemon */
153    for (j=0; j<i; j++) {
154       do_storage_status(ua, unique_store[j]);
155    }
156    free(unique_store);
157
158    /* Count Client items */
159    LockRes();
160    client = NULL;
161    for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
162       { }
163    unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
164    /* Find Unique Client address/port */         
165    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
166    i = 0;
167    unique_client[i++] = client;
168    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
169       found = 0;
170       for (j=0; j<i; j++) {
171          if (strcmp(unique_client[j]->address, client->address) == 0 &&
172              unique_client[j]->FDport == client->FDport) {
173             found = 1;
174             break;
175          }
176       }
177       if (!found) {
178          unique_client[i++] = client;
179          Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport);
180       }
181    }
182    UnlockRes();
183
184    /* Call each unique File daemon */
185    for (j=0; j<i; j++) {
186       do_client_status(ua, unique_client[j]);
187    }
188    free(unique_client);
189    
190 }
191
192 static void do_director_status(UAContext *ua, char *cmd)
193 {
194    JCR *jcr;
195    int njobs = 0;
196    char *msg;
197    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
198    int pool_mem = FALSE;
199
200    Dmsg0(200, "Doing status\n");
201    bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
202    bstrftime(dt, sizeof(dt), daemon_start_time);
203    bsendmsg(ua, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
204         last_job.NumJobs == 1 ? "" : "s");
205    if (last_job.NumJobs > 0) {
206       char termstat[30];
207
208       bstrftime(dt, sizeof(dt), last_job.end_time);
209       bsendmsg(ua, _("Last Job %s finished at %s\n"), last_job.Job, dt);
210       jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat));
211            
212       bsendmsg(ua, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
213            edit_uint64_with_commas(last_job.JobFiles, b1),
214            edit_uint64_with_commas(last_job.JobBytes, b2),
215            termstat);
216    }
217    lock_jcr_chain();
218    for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
219       if (jcr->JobId == 0) {      /* this is us */
220          bstrftime(dt, sizeof(dt), jcr->start_time);
221          bsendmsg(ua, _("Console connected at %s\n"), dt);
222          free_locked_jcr(jcr);
223          njobs--;
224          continue;
225       }
226       switch (jcr->JobStatus) {
227          case JS_Created:
228             msg = _("is waiting execution");
229             break;
230          case JS_Running:
231             msg = _("is running");
232             break;
233          case JS_Blocked:
234             msg = _("is blocked");
235             break;
236          case JS_Terminated:
237             msg = _("has terminated");
238             break;
239          case JS_ErrorTerminated:
240             msg = _("has erred");
241             break;
242          case JS_Cancelled:
243             msg = _("has been canceled");
244             break;
245          case JS_WaitFD:
246             msg = (char *) get_pool_memory(PM_FNAME);
247             Mmsg(&msg, _("is waiting on Client %s"), jcr->client->hdr.name);
248             pool_mem = TRUE;
249             break;
250          case JS_WaitSD:
251             msg = (char *) get_pool_memory(PM_FNAME);
252             Mmsg(&msg, _("is waiting on Storage %s"), jcr->store->hdr.name);
253             pool_mem = TRUE;
254             break;
255          default:
256             msg = (char *) get_pool_memory(PM_FNAME);
257             Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
258             pool_mem = TRUE;
259             break;
260       }
261       switch (jcr->SDJobStatus) {
262          case JS_WaitMount:
263             if (pool_mem) {
264                free_pool_memory(msg);
265                pool_mem = FALSE;
266             }
267             msg = _("is waiting for a mount request");
268             break;
269          case JS_WaitMedia:
270             if (pool_mem) {
271                free_pool_memory(msg);
272                pool_mem = FALSE;
273             }
274             msg = _("is waiting for an appendable Volume");
275             break;
276          case JS_WaitFD:
277             if (!pool_mem) {
278                msg = (char *) get_pool_memory(PM_FNAME);
279                pool_mem = TRUE;
280             }
281             Mmsg(&msg, _("is waiting for Client %s to connect to Storage %s"),
282                  jcr->client->hdr.name, jcr->store->hdr.name);
283             break;
284
285       }
286       bsendmsg(ua, _("JobId %d Job %s %s.\n"), jcr->JobId, jcr->Job, msg);
287       if (pool_mem) {
288          free_pool_memory(msg);
289          pool_mem = FALSE;
290       }
291       free_locked_jcr(jcr);
292    }
293    unlock_jcr_chain();
294
295    if (njobs == 0) {
296       bsendmsg(ua, _("No jobs are running.\n"));
297    }
298    print_jobs_scheduled(ua);
299    bsendmsg(ua, "====\n");
300 }
301
302 static void do_storage_status(UAContext *ua, STORE *store)
303 {
304    BSOCK *sd;
305
306    ua->jcr->store = store;
307    /* Try connecting for up to 15 seconds */
308    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
309       store->hdr.name, store->address, store->SDport);
310    if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
311       bsendmsg(ua, _("\nFailed to connect to Storage daemon %s.\n====\n"),
312          store->hdr.name);
313       return;
314    }
315    Dmsg0(20, _("Connected to storage daemon\n"));
316    sd = ua->jcr->store_bsock;
317    bnet_fsend(sd, "status");
318    while (bnet_recv(sd) >= 0) {
319       bsendmsg(ua, "%s", sd->msg);
320    }
321    bnet_sig(sd, BNET_TERMINATE);
322    bnet_close(sd);
323    ua->jcr->store_bsock = NULL;
324    return;  
325 }
326    
327 static void do_client_status(UAContext *ua, CLIENT *client)
328 {
329    BSOCK *fd;
330
331    /* Connect to File daemon */
332
333    ua->jcr->client = client;
334    /* Try to connect for 15 seconds */
335    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
336       client->hdr.name, client->address, client->FDport);
337    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
338       bsendmsg(ua, _("Failed to connect to Client %s.\n====\n"),
339          client->hdr.name);
340       return;
341    }
342    Dmsg0(20, _("Connected to file daemon\n"));
343    fd = ua->jcr->file_bsock;
344    bnet_fsend(fd, "status");
345    while (bnet_recv(fd) >= 0) {
346       bsendmsg(ua, "%s", fd->msg);
347    }
348    bnet_sig(fd, BNET_TERMINATE);
349    bnet_close(fd);
350    ua->jcr->file_bsock = NULL;
351
352    return;  
353 }
354
355 static void prt_runhdr(UAContext *ua)
356 {
357    bsendmsg(ua, _("Level          Type     Scheduled          Name\n"));
358    bsendmsg(ua, _("=================================================================\n"));
359 }
360
361 static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime)
362 {
363    char dt[MAX_TIME_LENGTH];       
364
365    bstrftime(dt, sizeof(dt), runtime);
366    bsendmsg(ua, _("%-14s %-8s %-18s %s\n"), 
367       level_to_str(level), job_type_to_str(job->JobType), dt, job->hdr.name);
368 }
369
370 /*          
371  * Find all jobs to be run this hour
372  * and the next hour.
373  */
374 static void print_jobs_scheduled(UAContext *ua)
375 {
376    time_t now, runtime, tomorrow;
377    RUN *run;
378    JOB *job;
379    SCHED *sched;
380    struct tm tm;
381    int mday, wday, month, wpos, tmday, twday, tmonth, twpos, i, hour;
382    int tod, tom;
383    int found;
384    int hdr_printed = FALSE;
385    int level;
386
387    Dmsg0(200, "enter find_runs()\n");
388
389    now = time(NULL);
390    localtime_r(&now, &tm);
391    mday = tm.tm_mday - 1;
392    wday = tm.tm_wday;
393    month = tm.tm_mon;
394    wpos = (tm.tm_mday - 1) / 7;
395
396    tomorrow = now + 60 * 60 * 24;
397    localtime_r(&tomorrow, &tm);
398    tmday = tm.tm_mday - 1;
399    twday = tm.tm_wday;
400    tmonth = tm.tm_mon;
401    twpos  = (tm.tm_mday - 1) / 7;
402
403    /* Loop through all jobs */
404    LockRes();
405    for (job=NULL; (job=(JOB *)GetNextRes(R_JOB, (RES *)job)); ) {
406       level = job->level;   
407       sched = job->schedule;
408       if (sched == NULL) {            /* scheduled? */
409          continue;                    /* no, skip this job */
410       }
411       for (run=sched->run; run; run=run->next) {
412          if (run->level) {
413             level = run->level;
414          }
415          /* 
416           * Find runs in next 24 hours
417           */
418          tod = (bit_is_set(mday, run->mday) || bit_is_set(wday, run->wday)) && 
419                 bit_is_set(month, run->month) && bit_is_set(wpos, run->wpos);
420
421          tom = (bit_is_set(tmday, run->mday) || bit_is_set(twday, run->wday)) &&
422                 bit_is_set(tmonth, run->month) && bit_is_set(wpos, run->wpos);
423
424          Dmsg2(200, "tod=%d tom=%d\n", tod, tom);
425          found = FALSE;
426          if (tod) {
427             /* find time (time_t) job is to be run */
428             localtime_r(&now, &tm);
429             hour = 0;
430             for (i=tm.tm_hour; i < 24; i++) {
431                if (bit_is_set(i, run->hour)) {
432                   tm.tm_hour = i;
433                   tm.tm_min = run->minute;
434                   tm.tm_sec = 0;
435                   runtime = mktime(&tm);
436                   if (runtime > now) {
437                      if (!hdr_printed) {
438                         hdr_printed = TRUE;
439                         prt_runhdr(ua);
440                      }
441                      prt_runtime(ua, job, level, runtime);
442                      found = TRUE;
443                      break;
444                   }
445                }
446             }
447          }
448
449 //      Dmsg2(200, "runtime=%d now=%d\n", runtime, now);
450         if (!found && tom) {
451             localtime_r(&tomorrow, &tm);
452             hour = 0;
453             for (i=0; i < 24; i++) {
454                if (bit_is_set(i, run->hour)) {
455                   hour = i;
456                   break;
457                }
458             }
459             tm.tm_hour = hour;
460             tm.tm_min = run->minute;
461             tm.tm_sec = 0;
462             runtime = mktime(&tm);
463             Dmsg2(200, "truntime=%d now=%d\n", runtime, now);
464             if (runtime < tomorrow) {
465                if (!hdr_printed) {
466                   hdr_printed = TRUE;
467                   prt_runhdr(ua);
468                }
469                prt_runtime(ua, job, level, runtime);
470             }
471          }
472       }  
473    }
474    UnlockRes();
475    Dmsg0(200, "Leave find_runs()\n");
476 }