]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_status.c
cater for create_bacula_database and grant_bacula_privileges
[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
33 extern char my_name[];
34 extern time_t daemon_start_time;
35 extern struct s_last_job last_job;
36
37 static void list_scheduled_jobs(UAContext *ua);
38 static void list_running_jobs(UAContext *ua);
39 static void list_terminated_jobs(UAContext *ua);
40 static void do_storage_status(UAContext *ua, STORE *store);
41 static void do_client_status(UAContext *ua, CLIENT *client);
42 static void do_director_status(UAContext *ua, char *cmd);
43 static void do_all_status(UAContext *ua, char *cmd);
44
45 /*
46  * status command
47  */
48 int status_cmd(UAContext *ua, char *cmd)
49 {
50    STORE *store;
51    CLIENT *client;
52    int item, i;
53
54    if (!open_db(ua)) {
55       return 1;
56    }
57    Dmsg1(20, "status:%s:\n", cmd);
58
59    for (i=1; i<ua->argc; i++) {
60       if (strcasecmp(ua->argk[i], _("all")) == 0) {
61          do_all_status(ua, cmd);
62          return 1;
63       } else if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
64                  strcasecmp(ua->argk[i], _("director")) == 0) {
65          do_director_status(ua, cmd);
66          return 1;
67       } else if (strcasecmp(ua->argk[i], _("client")) == 0) {
68          client = get_client_resource(ua);
69          if (client) {
70             do_client_status(ua, client);
71          }
72          return 1;
73       } else {
74          store = get_storage_resource(ua, 0);
75          if (store) {
76             do_storage_status(ua, store);
77          }
78          return 1;
79       }
80    }
81    /* If no args, ask for status type */
82    if (ua->argc == 1) {                                    
83       start_prompt(ua, _("Status available for:\n"));
84       add_prompt(ua, _("Director"));
85       add_prompt(ua, _("Storage"));
86       add_prompt(ua, _("Client"));
87       add_prompt(ua, _("All"));
88       Dmsg0(20, "do_prompt: select daemon\n");
89       if ((item=do_prompt(ua, "",  _("Select daemon type for status"), cmd, MAX_NAME_LENGTH)) < 0) {
90          return 1;
91       }
92       Dmsg1(20, "item=%d\n", item);
93       switch (item) { 
94       case 0:                         /* Director */
95          do_director_status(ua, cmd);
96          break;
97       case 1:
98          store = select_storage_resource(ua);
99          if (store) {
100             do_storage_status(ua, store);
101          }
102          break;
103       case 2:
104          client = select_client_resource(ua);
105          if (client) {
106             do_client_status(ua, client);
107          }
108          break;
109       case 3:
110          do_all_status(ua, cmd);
111          break;
112       default:
113          break;
114       }
115    }
116    return 1;
117 }
118
119 static void do_all_status(UAContext *ua, char *cmd)
120 {
121    STORE *store, **unique_store;
122    CLIENT *client, **unique_client;
123    int i, j, found;
124
125    do_director_status(ua, cmd);
126
127    /* Count Storage items */
128    LockRes();
129    store = NULL;
130    for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
131       { }
132    unique_store = (STORE **) malloc(i * sizeof(STORE));
133    /* Find Unique Storage address/port */         
134    store = (STORE *)GetNextRes(R_STORAGE, NULL);
135    i = 0;
136    unique_store[i++] = store;
137    while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
138       found = 0;
139       for (j=0; j<i; j++) {
140          if (strcmp(unique_store[j]->address, store->address) == 0 &&
141              unique_store[j]->SDport == store->SDport) {
142             found = 1;
143             break;
144          }
145       }
146       if (!found) {
147          unique_store[i++] = store;
148          Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport);
149       }
150    }
151    UnlockRes();
152
153    /* Call each unique Storage daemon */
154    for (j=0; j<i; j++) {
155       do_storage_status(ua, unique_store[j]);
156    }
157    free(unique_store);
158
159    /* Count Client items */
160    LockRes();
161    client = NULL;
162    for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
163       { }
164    unique_client = (CLIENT **)malloc(i * sizeof(CLIENT));
165    /* Find Unique Client address/port */         
166    client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
167    i = 0;
168    unique_client[i++] = client;
169    while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
170       found = 0;
171       for (j=0; j<i; j++) {
172          if (strcmp(unique_client[j]->address, client->address) == 0 &&
173              unique_client[j]->FDport == client->FDport) {
174             found = 1;
175             break;
176          }
177       }
178       if (!found) {
179          unique_client[i++] = client;
180          Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport);
181       }
182    }
183    UnlockRes();
184
185    /* Call each unique File daemon */
186    for (j=0; j<i; j++) {
187       do_client_status(ua, unique_client[j]);
188    }
189    free(unique_client);
190    
191 }
192
193 static void do_director_status(UAContext *ua, char *cmd)
194 {
195    char dt[MAX_TIME_LENGTH];
196
197    bsendmsg(ua, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
198             HOST_OS, DISTNAME, DISTVER);
199    bstrftime(dt, sizeof(dt), daemon_start_time);
200    bsendmsg(ua, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
201         last_job.NumJobs == 1 ? "" : "s");
202    /*
203     * List scheduled Jobs
204     */
205    list_scheduled_jobs(ua);
206
207    /* 
208     * List running jobs
209     */
210    list_running_jobs(ua);
211
212    /* 
213     * List terminated jobs
214     */
215    list_terminated_jobs(ua);
216    bsendmsg(ua, "====\n");
217 }
218
219 static void do_storage_status(UAContext *ua, STORE *store)
220 {
221    BSOCK *sd;
222
223    ua->jcr->store = store;
224    /* Try connecting for up to 15 seconds */
225    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"), 
226       store->hdr.name, store->address, store->SDport);
227    if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
228       bsendmsg(ua, _("\nFailed to connect to Storage daemon %s.\n====\n"),
229          store->hdr.name);
230       if (ua->jcr->store_bsock) {
231          bnet_close(ua->jcr->store_bsock);
232          ua->jcr->store_bsock = NULL;
233       }         
234       return;
235    }
236    Dmsg0(20, _("Connected to storage daemon\n"));
237    sd = ua->jcr->store_bsock;
238    bnet_fsend(sd, "status");
239    while (bnet_recv(sd) >= 0) {
240       bsendmsg(ua, "%s", sd->msg);
241    }
242    bnet_sig(sd, BNET_TERMINATE);
243    bnet_close(sd);
244    ua->jcr->store_bsock = NULL;
245    return;  
246 }
247    
248 static void do_client_status(UAContext *ua, CLIENT *client)
249 {
250    BSOCK *fd;
251
252    /* Connect to File daemon */
253
254    ua->jcr->client = client;
255    /* Release any old dummy key */
256    if (ua->jcr->sd_auth_key) {
257       free(ua->jcr->sd_auth_key);
258    }
259    /* Create a new dummy SD auth key */
260    ua->jcr->sd_auth_key = bstrdup("dummy");
261
262    /* Try to connect for 15 seconds */
263    bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"), 
264       client->hdr.name, client->address, client->FDport);
265    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
266       bsendmsg(ua, _("Failed to connect to Client %s.\n====\n"),
267          client->hdr.name);
268       if (ua->jcr->file_bsock) {
269          bnet_close(ua->jcr->file_bsock);
270          ua->jcr->file_bsock = NULL;
271       }         
272       return;
273    }
274    Dmsg0(20, _("Connected to file daemon\n"));
275    fd = ua->jcr->file_bsock;
276    bnet_fsend(fd, "status");
277    while (bnet_recv(fd) >= 0) {
278       bsendmsg(ua, "%s", fd->msg);
279    }
280    bnet_sig(fd, BNET_TERMINATE);
281    bnet_close(fd);
282    ua->jcr->file_bsock = NULL;
283
284    return;  
285 }
286
287 static void prt_runhdr(UAContext *ua)
288 {
289    bsendmsg(ua, _("\nScheduled Jobs:\n"));
290    bsendmsg(ua, _("Level          Type     Scheduled          Name               Volume\n"));
291    bsendmsg(ua, _("===============================================================================\n"));
292 }
293
294 static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime, POOL *pool)
295 {
296    char dt[MAX_TIME_LENGTH];       
297    char *level_ptr;
298    bool ok = false;
299    bool close_db = false;
300    JCR *jcr = ua->jcr;
301    MEDIA_DBR mr;
302    memset(&mr, 0, sizeof(mr));
303    if (job->JobType == JT_BACKUP) {
304       jcr->db = NULL;
305       ok = complete_jcr_for_job(jcr, job, pool);
306       if (jcr->db) {
307          close_db = true;             /* new db opened, remember to close it */
308       }
309       if (ok) {
310          ok = find_next_volume_for_append(jcr, &mr, 0);
311       }
312       if (!ok) {
313          bstrncpy(mr.VolumeName, "*unknown*", sizeof(mr.VolumeName));
314       }
315    }
316    bstrftime(dt, sizeof(dt), runtime);
317    switch (job->JobType) {
318    case JT_ADMIN:
319    case JT_RESTORE:
320       level_ptr = " ";
321       break;
322    default:
323       level_ptr = level_to_str(level);
324       break;
325    }
326    bsendmsg(ua, _("%-14s %-8s %-18s %-18s %s\n"), 
327       level_ptr, job_type_to_str(job->JobType), dt, job->hdr.name, mr.VolumeName);
328    if (close_db) {
329       db_close_database(jcr, jcr->db);
330    }
331    jcr->db = ua->db;                  /* restore ua db to jcr */
332
333 }
334
335 /*          
336  * Find all jobs to be run in roughly the
337  *  next 24 hours.
338  */
339 static void list_scheduled_jobs(UAContext *ua)
340 {
341    time_t runtime;
342    RUN *run;
343    JOB *job;
344    int level, num_jobs = 0;
345    bool hdr_printed = false;
346
347    Dmsg0(200, "enter find_runs()\n");
348
349    /* Loop through all jobs */
350    LockRes();
351    for (job=NULL; (job=(JOB *)GetNextRes(R_JOB, (RES *)job)); ) {
352       for (run=NULL; (run = find_next_run(run, job, runtime)); ) {
353          level = job->level;   
354          if (run->level) {
355             level = run->level;
356          }
357          if (!hdr_printed) {
358             prt_runhdr(ua);
359             hdr_printed = true;
360          }
361          prt_runtime(ua, job, level, runtime, run->pool);
362          num_jobs++;
363       }
364
365    } /* end for loop over resources */
366    UnlockRes();
367    if (num_jobs == 0) {
368       bsendmsg(ua, _("No Scheduled Jobs.\n"));
369    } else {
370       bsendmsg(ua, "\n");
371    }
372    Dmsg0(200, "Leave find_runs()\n");
373 }
374
375 static void list_running_jobs(UAContext *ua)
376 {
377    JCR *jcr;
378    int njobs = 0;
379    char *msg;
380    char dt[MAX_TIME_LENGTH];
381    char level[10];
382    bool pool_mem = false;
383
384    lock_jcr_chain();
385    for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
386       if (jcr->JobId == 0) {      /* this is us */
387          bstrftime(dt, sizeof(dt), jcr->start_time);
388          bsendmsg(ua, _("Console connected at %s\n"), dt);
389          njobs--;
390       }
391       free_locked_jcr(jcr);
392    }
393    if (njobs == 0) {
394       unlock_jcr_chain();
395       bsendmsg(ua, _("No Running Jobs.\n"));
396       return;
397    }
398    njobs = 0;
399    bsendmsg(ua, _("\nRunning Jobs:\n"));
400    bsendmsg(ua, _("Level JobId  Job                        Status\n"));
401    bsendmsg(ua, _("====================================================================\n"));
402    for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
403       if (jcr->JobId == 0) {      /* this is us */
404          njobs--;
405          free_locked_jcr(jcr);
406          continue;
407       }
408       switch (jcr->JobStatus) {
409       case JS_Created:
410          msg = _("is waiting execution");
411          break;
412       case JS_Running:
413          msg = _("is running");
414          break;
415       case JS_Blocked:
416          msg = _("is blocked");
417          break;
418       case JS_Terminated:
419          msg = _("has terminated");
420          break;
421       case JS_ErrorTerminated:
422          msg = _("has erred");
423          break;
424       case JS_Error:
425          msg = _("has errors");
426          break;
427       case JS_FatalError:
428          msg = _("has a fatal error");
429          break;
430       case JS_Differences:
431          msg = _("has verify differences");
432          break;
433       case JS_Canceled:
434          msg = _("has been canceled");
435          break;
436       case JS_WaitFD:
437          msg = (char *) get_pool_memory(PM_FNAME);
438          Mmsg(&msg, _("is waiting on Client %s"), jcr->client->hdr.name);
439          pool_mem = true;
440          break;
441       case JS_WaitSD:
442          msg = (char *) get_pool_memory(PM_FNAME);
443          Mmsg(&msg, _("is waiting on Storage %s"), jcr->store->hdr.name);
444          pool_mem = true;
445          break;
446       case JS_WaitStoreRes:
447          msg = _("is waiting on max Storage jobs");
448          break;
449       case JS_WaitClientRes:
450          msg = _("is waiting on max Client jobs");
451          break;
452       case JS_WaitJobRes:
453          msg = _("is waiting on max Job jobs");
454          break;
455       case JS_WaitMaxJobs:
456          msg = _("is waiting on max total jobs");
457          break;
458       case JS_WaitStartTime:
459          msg = _("is waiting for its start time");
460          break;
461       case JS_WaitPriority:
462          msg = _("is waiting for higher priority jobs to finish");
463          break;
464
465       default:
466          msg = (char *) get_pool_memory(PM_FNAME);
467          Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
468          pool_mem = true;
469          break;
470       }
471       /* 
472        * Now report Storage daemon status code 
473        */
474       switch (jcr->SDJobStatus) {
475       case JS_WaitMount:
476          if (pool_mem) {
477             free_pool_memory(msg);
478             pool_mem = false;
479          }
480          msg = _("is waiting for a mount request");
481          break;
482       case JS_WaitMedia:
483          if (pool_mem) {
484             free_pool_memory(msg);
485             pool_mem = false;
486          }
487          msg = _("is waiting for an appendable Volume");
488          break;
489       case JS_WaitFD:
490          if (!pool_mem) {
491             msg = (char *) get_pool_memory(PM_FNAME);
492             pool_mem = true;
493          }
494          Mmsg(&msg, _("is waiting for Client %s to connect to Storage %s"),
495               jcr->client->hdr.name, jcr->store->hdr.name);
496          break;
497       }
498       switch (jcr->JobType) {
499       case JT_ADMIN:
500       case JT_RESTORE:
501          bstrncpy(level, "    ", sizeof(level));
502          break;
503       default:
504          bstrncpy(level, level_to_str(jcr->JobLevel), sizeof(level));
505          level[4] = 0;
506          break;
507       }
508
509       bsendmsg(ua, _("%-4s %6d  %-20s %s\n"), 
510          level, 
511          jcr->JobId,
512          jcr->Job,
513          msg);
514
515       if (pool_mem) {
516          free_pool_memory(msg);
517          pool_mem = false;
518       }
519       free_locked_jcr(jcr);
520    }
521    unlock_jcr_chain();
522
523    bsendmsg(ua, "\n");
524 }
525
526 static void list_terminated_jobs(UAContext *ua)
527 {
528    char dt[MAX_TIME_LENGTH], b1[30], b2[30];
529    char level[10];
530
531    if (last_job.NumJobs == 0) {
532       bsendmsg(ua, _("No Terminated Jobs.\n"));
533       return;
534    }
535    lock_last_jobs_list();
536    struct s_last_job *je;
537    bsendmsg(ua, _("\nTerminated Jobs:\n"));
538    bsendmsg(ua, _("Level   Files        Bytes Status   Finished        Name \n"));
539    bsendmsg(ua, _("====================================================================\n"));
540    for (je=NULL; (je=(s_last_job *)last_jobs->next(je)); ) {
541       char JobName[MAX_NAME_LENGTH];
542       char *termstat;
543
544       bstrftime(dt, sizeof(dt), je->end_time);
545       strcpy(dt+7, dt+9);     /* cut century */
546       switch (je->JobType) {
547       case JT_ADMIN:
548       case JT_RESTORE:
549          bstrncpy(level, "    ", sizeof(level));
550          break;
551       default:
552          bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
553          level[4] = 0;
554          break;
555       }
556       switch (je->JobStatus) {
557       case JS_Created:
558          termstat = "Created";
559          break;
560       case JS_FatalError:
561       case JS_ErrorTerminated:
562          termstat = "Error";
563          break;
564       case JS_Differences:
565          termstat = "Diffs";
566          break;
567       case JS_Canceled:
568          termstat = "Cancel";
569          break;
570       case JS_Terminated:
571          termstat = "OK";
572          break;
573       default:
574          termstat = "Other";
575          break;
576       }
577       bstrncpy(JobName, je->Job, sizeof(JobName));
578       /* There are three periods after the Job name */
579       char *p;
580       for (int i=0; i<3; i++) {
581          if ((p=strrchr(JobName, '.')) != NULL) {
582             *p = 0;
583          }
584       }
585       bsendmsg(ua, _("%-4s %8s %12s %-7s  %-8s %s\n"), 
586          level, 
587          edit_uint64_with_commas(je->JobFiles, b1),
588          edit_uint64_with_commas(je->JobBytes, b2), 
589          termstat,
590          dt, JobName);
591    }
592    bsendmsg(ua, "\n");
593    unlock_last_jobs_list();
594 }