3 * Bacula Director -- User Agent Status Command
5 * Kern Sibbald, August MMI
11 Copyright (C) 2000-2003 Kern Sibbald and John Walker
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.
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.
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,
33 extern char my_name[];
34 extern time_t daemon_start_time;
35 extern struct s_last_job last_job;
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);
48 int status_cmd(UAContext *ua, char *cmd)
57 Dmsg1(20, "status:%s:\n", cmd);
59 for (i=1; i<ua->argc; i++) {
60 if (strcasecmp(ua->argk[i], _("all")) == 0) {
61 do_all_status(ua, cmd);
63 } else if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
64 strcasecmp(ua->argk[i], _("director")) == 0) {
65 do_director_status(ua, cmd);
67 } else if (strcasecmp(ua->argk[i], _("client")) == 0) {
68 client = get_client_resource(ua);
70 do_client_status(ua, client);
74 store = get_storage_resource(ua, 0);
76 do_storage_status(ua, store);
81 /* If no args, ask for status type */
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) {
92 Dmsg1(20, "item=%d\n", item);
94 case 0: /* Director */
95 do_director_status(ua, cmd);
98 store = select_storage_resource(ua);
100 do_storage_status(ua, store);
104 client = select_client_resource(ua);
106 do_client_status(ua, client);
110 do_all_status(ua, cmd);
119 static void do_all_status(UAContext *ua, char *cmd)
121 STORE *store, **unique_store;
122 CLIENT *client, **unique_client;
126 do_director_status(ua, cmd);
128 /* Count Storage items */
131 foreach_res(store, R_STORAGE) {
134 unique_store = (STORE **) malloc(i * sizeof(STORE));
135 /* Find Unique Storage address/port */
137 foreach_res(store, R_STORAGE) {
139 if (!acl_access_ok(ua, Storage_ACL, store->hdr.name)) {
142 for (j=0; j<i; j++) {
143 if (strcmp(unique_store[j]->address, store->address) == 0 &&
144 unique_store[j]->SDport == store->SDport) {
150 unique_store[i++] = store;
151 Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport);
156 /* Call each unique Storage daemon */
157 for (j=0; j<i; j++) {
158 do_storage_status(ua, unique_store[j]);
162 /* Count Client items */
165 foreach_res(client, R_CLIENT) {
168 unique_client = (CLIENT **)malloc(i * sizeof(CLIENT));
169 /* Find Unique Client address/port */
171 foreach_res(client, R_CLIENT) {
173 if (!acl_access_ok(ua, Client_ACL, client->hdr.name)) {
176 for (j=0; j<i; j++) {
177 if (strcmp(unique_client[j]->address, client->address) == 0 &&
178 unique_client[j]->FDport == client->FDport) {
184 unique_client[i++] = client;
185 Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport);
190 /* Call each unique File daemon */
191 for (j=0; j<i; j++) {
192 do_client_status(ua, unique_client[j]);
198 static void do_director_status(UAContext *ua, char *cmd)
200 char dt[MAX_TIME_LENGTH];
202 bsendmsg(ua, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
203 HOST_OS, DISTNAME, DISTVER);
204 bstrftime_nc(dt, sizeof(dt), daemon_start_time);
205 bsendmsg(ua, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
206 last_job.NumJobs == 1 ? "" : "s");
208 * List scheduled Jobs
210 list_scheduled_jobs(ua);
215 list_running_jobs(ua);
218 * List terminated jobs
220 list_terminated_jobs(ua);
221 bsendmsg(ua, "====\n");
224 static void do_storage_status(UAContext *ua, STORE *store)
228 ua->jcr->store = store;
229 /* Try connecting for up to 15 seconds */
230 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"),
231 store->hdr.name, store->address, store->SDport);
232 if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
233 bsendmsg(ua, _("\nFailed to connect to Storage daemon %s.\n====\n"),
235 if (ua->jcr->store_bsock) {
236 bnet_close(ua->jcr->store_bsock);
237 ua->jcr->store_bsock = NULL;
241 Dmsg0(20, _("Connected to storage daemon\n"));
242 sd = ua->jcr->store_bsock;
243 bnet_fsend(sd, "status");
244 while (bnet_recv(sd) >= 0) {
245 bsendmsg(ua, "%s", sd->msg);
247 bnet_sig(sd, BNET_TERMINATE);
249 ua->jcr->store_bsock = NULL;
253 static void do_client_status(UAContext *ua, CLIENT *client)
257 /* Connect to File daemon */
259 ua->jcr->client = client;
260 /* Release any old dummy key */
261 if (ua->jcr->sd_auth_key) {
262 free(ua->jcr->sd_auth_key);
264 /* Create a new dummy SD auth key */
265 ua->jcr->sd_auth_key = bstrdup("dummy");
267 /* Try to connect for 15 seconds */
268 bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
269 client->hdr.name, client->address, client->FDport);
270 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
271 bsendmsg(ua, _("Failed to connect to Client %s.\n====\n"),
273 if (ua->jcr->file_bsock) {
274 bnet_close(ua->jcr->file_bsock);
275 ua->jcr->file_bsock = NULL;
279 Dmsg0(20, _("Connected to file daemon\n"));
280 fd = ua->jcr->file_bsock;
281 bnet_fsend(fd, "status");
282 while (bnet_recv(fd) >= 0) {
283 bsendmsg(ua, "%s", fd->msg);
285 bnet_sig(fd, BNET_TERMINATE);
287 ua->jcr->file_bsock = NULL;
292 static void prt_runhdr(UAContext *ua)
294 bsendmsg(ua, _("\nScheduled Jobs:\n"));
295 bsendmsg(ua, _("Level Type Scheduled Name Volume\n"));
296 bsendmsg(ua, _("===============================================================================\n"));
299 static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime, POOL *pool)
301 char dt[MAX_TIME_LENGTH];
304 bool close_db = false;
307 memset(&mr, 0, sizeof(mr));
308 if (job->JobType == JT_BACKUP) {
310 ok = complete_jcr_for_job(jcr, job, pool);
312 close_db = true; /* new db opened, remember to close it */
315 ok = find_next_volume_for_append(jcr, &mr, 0);
318 bstrncpy(mr.VolumeName, "*unknown*", sizeof(mr.VolumeName));
321 bstrftime_nc(dt, sizeof(dt), runtime);
322 switch (job->JobType) {
328 level_ptr = level_to_str(level);
331 bsendmsg(ua, _("%-14s %-8s %-18s %-18s %s\n"),
332 level_ptr, job_type_to_str(job->JobType), dt, job->hdr.name, mr.VolumeName);
334 db_close_database(jcr, jcr->db);
336 jcr->db = ua->db; /* restore ua db to jcr */
341 * Find all jobs to be run in roughly the
344 static void list_scheduled_jobs(UAContext *ua)
349 int level, num_jobs = 0;
350 bool hdr_printed = false;
352 Dmsg0(200, "enter find_runs()\n");
354 /* Loop through all jobs */
356 foreach_res(job, R_JOB) {
357 if (!acl_access_ok(ua, Job_ACL, job->hdr.name)) {
360 for (run=NULL; (run = find_next_run(run, job, runtime)); ) {
369 prt_runtime(ua, job, level, runtime, run->pool);
373 } /* end for loop over resources */
376 bsendmsg(ua, _("No Scheduled Jobs.\n"));
380 Dmsg0(200, "Leave find_runs()\n");
383 static void list_running_jobs(UAContext *ua)
388 char dt[MAX_TIME_LENGTH];
390 bool pool_mem = false;
393 for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
394 if (jcr->JobId == 0) { /* this is us */
395 /* this is a console or other control job. We only show console
396 * jobs in the status output.
398 if (jcr->JobType == JT_CONSOLE) {
399 bstrftime_nc(dt, sizeof(dt), jcr->start_time);
400 bsendmsg(ua, _("Console connected at %s\n"), dt);
404 free_locked_jcr(jcr);
408 bsendmsg(ua, _("No Running Jobs.\n"));
412 bsendmsg(ua, _("\nRunning Jobs:\n"));
413 bsendmsg(ua, _("Level JobId Job Status\n"));
414 bsendmsg(ua, _("====================================================================\n"));
415 for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
416 if (!acl_access_ok(ua, Job_ACL, jcr->job->hdr.name)) {
419 if (jcr->JobId == 0) { /* this is us */
421 free_locked_jcr(jcr);
424 switch (jcr->JobStatus) {
426 msg = _("is waiting execution");
429 msg = _("is running");
432 msg = _("is blocked");
435 msg = _("has terminated");
437 case JS_ErrorTerminated:
438 msg = _("has erred");
441 msg = _("has errors");
444 msg = _("has a fatal error");
447 msg = _("has verify differences");
450 msg = _("has been canceled");
453 msg = (char *) get_pool_memory(PM_FNAME);
454 Mmsg(&msg, _("is waiting on Client %s"), jcr->client->hdr.name);
458 msg = (char *) get_pool_memory(PM_FNAME);
459 Mmsg(&msg, _("is waiting on Storage %s"), jcr->store->hdr.name);
462 case JS_WaitStoreRes:
463 msg = _("is waiting on max Storage jobs");
465 case JS_WaitClientRes:
466 msg = _("is waiting on max Client jobs");
469 msg = _("is waiting on max Job jobs");
472 msg = _("is waiting on max total jobs");
474 case JS_WaitStartTime:
475 msg = _("is waiting for its start time");
477 case JS_WaitPriority:
478 msg = _("is waiting for higher priority jobs to finish");
482 msg = (char *) get_pool_memory(PM_FNAME);
483 Mmsg(&msg, _("is in unknown state %c"), jcr->JobStatus);
488 * Now report Storage daemon status code
490 switch (jcr->SDJobStatus) {
493 free_pool_memory(msg);
496 msg = _("is waiting for a mount request");
500 free_pool_memory(msg);
503 msg = _("is waiting for an appendable Volume");
507 msg = (char *) get_pool_memory(PM_FNAME);
510 Mmsg(&msg, _("is waiting for Client %s to connect to Storage %s"),
511 jcr->client->hdr.name, jcr->store->hdr.name);
514 switch (jcr->JobType) {
517 bstrncpy(level, " ", sizeof(level));
520 bstrncpy(level, level_to_str(jcr->JobLevel), sizeof(level));
525 bsendmsg(ua, _("%-4s %6d %-20s %s\n"),
532 free_pool_memory(msg);
535 free_locked_jcr(jcr);
542 static void list_terminated_jobs(UAContext *ua)
544 char dt[MAX_TIME_LENGTH], b1[30], b2[30];
547 if (last_jobs->empty()) {
548 bsendmsg(ua, _("No Terminated Jobs.\n"));
551 lock_last_jobs_list();
552 struct s_last_job *je;
553 bsendmsg(ua, _("\nTerminated Jobs:\n"));
554 bsendmsg(ua, _(" JobId Level Files Bytes Status Finished Name \n"));
555 bsendmsg(ua, _("======================================================================\n"));
556 foreach_dlist(je, last_jobs) {
557 char JobName[MAX_NAME_LENGTH];
560 bstrftime_nc(dt, sizeof(dt), je->end_time);
561 switch (je->JobType) {
564 bstrncpy(level, " ", sizeof(level));
567 bstrncpy(level, level_to_str(je->JobLevel), sizeof(level));
571 switch (je->JobStatus) {
573 termstat = "Created";
576 case JS_ErrorTerminated:
592 bstrncpy(JobName, je->Job, sizeof(JobName));
593 /* There are three periods after the Job name */
595 for (int i=0; i<3; i++) {
596 if ((p=strrchr(JobName, '.')) != NULL) {
600 bsendmsg(ua, _("%6d %-4s %8s %14s %-7s %-8s %s\n"),
603 edit_uint64_with_commas(je->JobFiles, b1),
604 edit_uint64_with_commas(je->JobBytes, b2),
609 unlock_last_jobs_list();