]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_status.c
6d287c9d042cdd794b4894dfd308d0ff15971f17
[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, 2001, 2002 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)) < 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, jstat[2];
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       switch (last_job.JobStatus) {
211          case JS_Terminated:
212             termstat = _("OK");
213             break;
214         case JS_ErrorTerminated:
215             termstat = _("Error");
216             break;
217         default:
218             jstat[0] = last_job.JobStatus;
219             jstat[1] = 0;
220             termstat = jstat;
221             break;
222       }
223            
224       bsendmsg(ua, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
225            edit_uint64_with_commas(last_job.JobFiles, b1),
226            edit_uint64_with_commas(last_job.JobBytes, b2),
227            termstat);
228    }
229    lock_jcr_chain();
230    for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
231       if (jcr->JobId == 0) {      /* this is us */
232          bstrftime(dt, sizeof(dt), jcr->start_time);
233          bsendmsg(ua, _("Console connected at %s\n"), dt);
234          free_locked_jcr(jcr);
235          njobs--;
236          continue;
237       }
238       switch (jcr->JobStatus) {
239          case JS_Created:
240             msg = _("is waiting execution");
241             break;
242          case JS_Running:
243             msg = _("is running");
244             break;
245          case JS_Blocked:
246             msg = _("is blocked");
247             break;
248          case JS_Terminated:
249             msg = _("has terminated");
250             break;
251          case JS_ErrorTerminated:
252             msg = _("has erred");
253             break;
254          case JS_Cancelled:
255             msg = _("has been canceled");
256             break;
257          case JS_WaitFD:
258             msg = (char *) get_pool_memory(PM_FNAME);
259             Mmsg(&msg, _("is waiting on Client %s"), jcr->client->hdr.name);
260             pool_mem = TRUE;
261             break;
262          case JS_WaitSD:
263             msg = (char *) get_pool_memory(PM_FNAME);
264             Mmsg(&msg, _("is waiting on Storage %s"), jcr->store->hdr.name);
265             pool_mem = TRUE;
266             break;
267          default:
268             msg = (char *) get_pool_memory(PM_FNAME);
269             Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
270             pool_mem = TRUE;
271             break;
272       }
273       switch (jcr->SDJobStatus) {
274          case JS_WaitMount:
275             if (pool_mem) {
276                free_pool_memory(msg);
277                pool_mem = FALSE;
278             }
279             msg = _("is waiting for a mount request");
280             break;
281          case JS_WaitMedia:
282             if (pool_mem) {
283                free_pool_memory(msg);
284                pool_mem = FALSE;
285             }
286             msg = _("is waiting for an appendable Volume");
287             break;
288          case JS_WaitFD:
289             if (!pool_mem) {
290                msg = (char *) get_pool_memory(PM_FNAME);
291                pool_mem = TRUE;
292             }
293             Mmsg(&msg, _("is waiting for Client %s to connect to Storage %s"),
294                  jcr->client->hdr.name, jcr->store->hdr.name);
295             break;
296
297       }
298       bsendmsg(ua, _("JobId %d Job %s %s.\n"), jcr->JobId, jcr->Job, msg);
299       if (pool_mem) {
300          free_pool_memory(msg);
301          pool_mem = FALSE;
302       }
303       free_locked_jcr(jcr);
304    }
305    unlock_jcr_chain();
306
307    if (njobs == 0) {
308       bsendmsg(ua, _("No jobs are running.\n"));
309    }
310    print_jobs_scheduled(ua);
311    bsendmsg(ua, "====\n");
312 }
313
314 static void do_storage_status(UAContext *ua, STORE *store)
315 {
316    BSOCK *sd;
317
318    ua->jcr->store = store;
319    /* Try connecting for up to 15 seconds */
320    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
321       store->hdr.name, store->address, store->SDport);
322    if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
323       bsendmsg(ua, _("\nFailed to connect to Storage daemon %s.\n====\n"),
324          store->hdr.name);
325       return;
326    }
327    Dmsg0(20, _("Connected to storage daemon\n"));
328    sd = ua->jcr->store_bsock;
329    bnet_fsend(sd, "status");
330    while (bnet_recv(sd) > 0) {
331       bsendmsg(ua, "%s", sd->msg);
332    }
333    bnet_sig(sd, BNET_TERMINATE);
334    bnet_close(sd);
335    ua->jcr->store_bsock = NULL;
336    return;  
337 }
338    
339 static void do_client_status(UAContext *ua, CLIENT *client)
340 {
341    BSOCK *fd;
342
343    /* Connect to File daemon */
344
345    ua->jcr->client = client;
346    /* Try to connect for 15 seconds */
347    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
348       client->hdr.name, client->address, client->FDport);
349    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
350       bsendmsg(ua, _("Failed to connect to Client %s.\n====\n"),
351          client->hdr.name);
352       return;
353    }
354    Dmsg0(20, _("Connected to file daemon\n"));
355    fd = ua->jcr->file_bsock;
356    bnet_fsend(fd, "status");
357    while (bnet_recv(fd) > 0) {
358       bsendmsg(ua, "%s", fd->msg);
359    }
360    bnet_sig(fd, BNET_TERMINATE);
361    bnet_close(fd);
362    ua->jcr->file_bsock = NULL;
363
364    return;  
365 }
366
367 static void prt_runtime(UAContext *ua, JOB *job, time_t runtime)
368 {
369    char dt[MAX_TIME_LENGTH], *type;
370
371    bstrftime(dt, sizeof(dt), runtime);
372    switch (job->JobType) {
373       case JT_BACKUP:
374          type = _("Backup");
375          break;
376       case JT_VERIFY:
377          type = _("Verify");
378          break;
379       case JT_RESTORE:
380          type = _("Restore");
381          break;
382       default:
383          type = _("Unknown type of");
384          break;
385    }
386    bsendmsg(ua, _("%s job \"%s\" scheduled for %s\n"), type, job->hdr.name, dt);
387 }
388
389 /*          
390  * Find all jobs to be run this hour
391  * and the next hour.
392  */
393 static void print_jobs_scheduled(UAContext *ua)
394 {
395    time_t now, runtime, tomorrow;
396    RUN *run;
397    JOB *job;
398    SCHED *sched;
399    struct tm tm;
400    int mday, wday, month, tmday, twday, tmonth, i, hour;
401    int tod, tom;
402    int found;
403
404    Dmsg0(200, "enter find_runs()\n");
405
406    now = time(NULL);
407    localtime_r(&now, &tm);
408    mday = tm.tm_mday - 1;
409    wday = tm.tm_wday;
410    month = tm.tm_mon;
411
412    tomorrow = now + 60 * 60 * 24;
413    localtime_r(&tomorrow, &tm);
414    tmday = tm.tm_mday - 1;
415    twday = tm.tm_wday;
416    tmonth = tm.tm_mon;
417
418    /* Loop through all jobs */
419    LockRes();
420    for (job=NULL; (job=(JOB *)GetNextRes(R_JOB, (RES *)job)); ) {
421       sched = job->schedule;
422       if (sched == NULL) {            /* scheduled? */
423          continue;                    /* no, skip this job */
424       }
425       for (run=sched->run; run; run=run->next) {
426          /* 
427           * Find runs in next 24 hours
428           */
429          tod = (bit_is_set(mday, run->mday) || bit_is_set(wday, run->wday)) && 
430                 bit_is_set(month, run->month);
431
432          tom = (bit_is_set(tmday, run->mday) || bit_is_set(twday, run->wday)) &&
433                 bit_is_set(tmonth, run->month);
434
435          Dmsg2(200, "tod=%d tom=%d\n", tod, tom);
436          found = FALSE;
437          if (tod) {
438             /* find time (time_t) job is to be run */
439             localtime_r(&now, &tm);
440             hour = 0;
441             for (i=tm.tm_hour; i < 24; i++) {
442                if (bit_is_set(i, run->hour)) {
443                   tm.tm_hour = i;
444                   tm.tm_min = run->minute;
445                   tm.tm_sec = 0;
446                   runtime = mktime(&tm);
447                   if (runtime > now) {
448                      prt_runtime(ua, job, runtime);
449                      found = TRUE;
450                      break;
451                   }
452                }
453             }
454          }
455
456         Dmsg2(200, "runtime=%d now=%d\n", runtime, now);
457         if (!found && tom) {
458             localtime_r(&tomorrow, &tm);
459             hour = 0;
460             for (i=0; i < 24; i++) {
461                if (bit_is_set(i, run->hour)) {
462                   hour = i;
463                   break;
464                }
465             }
466             tm.tm_hour = hour;
467             tm.tm_min = run->minute;
468             tm.tm_sec = 0;
469             runtime = mktime(&tm);
470             Dmsg2(200, "truntime=%d now=%d\n", runtime, now);
471             if (runtime < tomorrow) {
472                prt_runtime(ua, job, runtime);
473             }
474          }
475       }  
476    }
477    UnlockRes();
478    Dmsg0(200, "Leave find_runs()\n");
479 }