Release Notes for Bacula 1.32
- Bacula code: Total files = 259 Total lines = 77,284 (*.h *.c *.in)
+ Bacula code: Total files = 259 Total lines = 77,334 (*.h *.c *.in)
Major Changes this Release:
- Fixed gnome-console to compile with RH9 (Gnome 2.0)
Kern's ToDo List
- 12 September 2003
+ 15 September 2003
Documentation to do: (any release a little bit at a time)
- Document running a test version.
- Figure out how to use ssh or stunnel to protect Bacula communications.
For 1.32:
+- Document list nextvol and new format status dir.
- Document new records in Director. SDAddress SDDeviceName, SDPassword.
FDPassword, FDAddress, DBAddress, DBPort, DBPassword.
- It is generally safe to use the drive when the lights stop flashing.
- Allow a slot or range of slots on the label barcodes command.
when the magazine is changed.
- Don't print "Warning: Wrong Volume mounted ..." if mounting second volume.
-- Implement List Volume Job=xxx or List scheduled volumes or Status Director
-- May variable expansion work correctly.
- LabelFormat on tape volume apparently creates the db record but
never actually labels the volume.
+- Copy static programs into install directory.
For 1.33
- Think about changing Storage resource Device record to be
- Document SDConnectTimeout (in FD).
- Add restore by filename test.
- Document restore by files.
+- Make variable expansion work correctly.
+- Implement List Volume Job=xxx or List scheduled volumes or Status Director
<widget>
<class>GtkWindow</class>
<name>app1</name>
- <width>800</width>
- <height>500</height>
<signal>
<name>delete_event</name>
<handler>on_app1_delete_event</handler>
<type>GTK_WINDOW_TOPLEVEL</type>
<position>GTK_WIN_POS_CENTER</position>
<modal>False</modal>
- <default_height>500</default_height>
<allow_shrink>True</allow_shrink>
<allow_grow>True</allow_grow>
- <auto_shrink>False</auto_shrink>
+ <auto_shrink>True</auto_shrink>
<widget>
<class>GtkVBox</class>
<type>GTK_WINDOW_TOPLEVEL</type>
<position>GTK_WIN_POS_CENTER</position>
<modal>True</modal>
- <allow_shrink>False</allow_shrink>
- <allow_grow>False</allow_grow>
+ <allow_shrink>True</allow_shrink>
+ <allow_grow>True</allow_grow>
<auto_shrink>False</auto_shrink>
<widget>
/*
- * Really crude automatic Volume name creation using
+ * Automatic Volume name creation using
* LabelFormat. We assume that if this routine is being
* called the Volume will be labeled, so we set the LabelDate.
*/
/* fd_cmds.c */
extern int connect_to_file_daemon(JCR *jcr, int retry_interval,
- int max_retry_time, int verbose);
+ int max_retry_time, int verbose);
extern int send_include_list(JCR *jcr);
extern int send_exclude_list(JCR *jcr);
extern int send_bootstrap_file(JCR *jcr);
extern int get_attributes_and_put_in_catalog(JCR *jcr);
extern int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId);
extern int put_file_into_catalog(JCR *jcr, long file_index, char *fname,
- char *link, char *attr, int stream);
+ char *link, char *attr, int stream);
extern void get_level_since_time(JCR *jcr, char *since, int since_len);
extern int send_run_before_and_after_commands(JCR *jcr);
/* msgchan.c */
extern int connect_to_storage_daemon(JCR *jcr, int retry_interval,
- int max_retry_time, int verbose);
+ int max_retry_time, int verbose);
extern int start_storage_daemon_job(JCR *jcr);
extern int start_storage_daemon_message_thread(JCR *jcr);
extern int bget_dirmsg(BSOCK *bs);
/* ua_output.c */
void prtit(void *ctx, char *msg);
+int complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool);
/* ua_server.c */
void bsendmsg(void *sock, char *fmt, ...);
void free_ua_context(UAContext *ua);
/* ua_select.c */
-STORE *select_storage_resource(UAContext *ua);
-JOB *select_job_resource(UAContext *ua);
-JOB *select_restore_job_resource(UAContext *ua);
-CLIENT *select_client_resource(UAContext *ua);
+STORE *select_storage_resource(UAContext *ua);
+JOB *select_job_resource(UAContext *ua);
+JOB *select_restore_job_resource(UAContext *ua);
+CLIENT *select_client_resource(UAContext *ua);
FILESET *select_fileset_resource(UAContext *ua);
-int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr);
-int select_media_dbr(UAContext *ua, MEDIA_DBR *mr);
-int select_pool_dbr(UAContext *ua, POOL_DBR *pr);
-int select_client_dbr(UAContext *ua, CLIENT_DBR *cr);
-
-void start_prompt(UAContext *ua, char *msg);
-void add_prompt(UAContext *ua, char *prompt);
-int do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt);
-CAT *get_catalog_resource(UAContext *ua);
+int select_pool_and_media_dbr(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr);
+int select_media_dbr(UAContext *ua, MEDIA_DBR *mr);
+int select_pool_dbr(UAContext *ua, POOL_DBR *pr);
+int select_client_dbr(UAContext *ua, CLIENT_DBR *cr);
+
+void start_prompt(UAContext *ua, char *msg);
+void add_prompt(UAContext *ua, char *prompt);
+int do_prompt(UAContext *ua, char *automsg, char *msg, char *prompt, int max_prompt);
+CAT *get_catalog_resource(UAContext *ua);
STORE *get_storage_resource(UAContext *ua, int use_default);
-int get_media_type(UAContext *ua, char *MediaType, int max_media);
-int get_pool_dbr(UAContext *ua, POOL_DBR *pr);
-int get_client_dbr(UAContext *ua, CLIENT_DBR *cr);
+int get_media_type(UAContext *ua, char *MediaType, int max_media);
+int get_pool_dbr(UAContext *ua, POOL_DBR *pr);
+int get_client_dbr(UAContext *ua, CLIENT_DBR *cr);
POOL *get_pool_resource(UAContext *ua);
POOL *select_pool_resource(UAContext *ua);
CLIENT *get_client_resource(UAContext *ua);
-int get_job_dbr(UAContext *ua, JOB_DBR *jr);
+int get_job_dbr(UAContext *ua, JOB_DBR *jr);
int find_arg_keyword(UAContext *ua, char **list);
int find_arg(UAContext *ua, char *keyword);
/* Imported functions */
extern int status_cmd(UAContext *ua, char *cmd);
-extern int listcmd(UAContext *ua, char *cmd);
-extern int llistcmd(UAContext *ua, char *cmd);
+extern int list_cmd(UAContext *ua, char *cmd);
+extern int llist_cmd(UAContext *ua, char *cmd);
extern int show_cmd(UAContext *ua, char *cmd);
extern int messagescmd(UAContext *ua, char *cmd);
extern int autodisplaycmd(UAContext *ua, char *cmd);
{ N_("exit"), quit_cmd, _("exit = quit")},
{ N_("help"), help_cmd, _("print this command")},
{ N_("label"), label_cmd, _("label a tape")},
- { N_("list"), listcmd, _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
- { N_("llist"), llistcmd, _("full or long list like list command")},
+ { N_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
+ { N_("llist"), llist_cmd, _("full or long list like list command")},
{ N_("messages"), messagescmd, _("messages")},
{ N_("mount"), mount_cmd, _("mount <storage-name>")},
{ N_("prune"), prunecmd, _("prune expired records from catalog")},
/* Imported functions */
/* Forward referenced functions */
-static int do_listcmd(UAContext *ua, char *cmd, e_list_type llist);
-
+static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist);
/*
* Turn auto display of console messages on/off
NULL};
switch (find_arg_keyword(ua, kw)) {
- case 0:
- ua->auto_display_messages = 1;
- break;
- case 1:
- ua->auto_display_messages = 0;
- break;
- default:
- bsendmsg(ua, _("ON or OFF keyword missing.\n"));
- break;
+ case 0:
+ ua->auto_display_messages = 1;
+ break;
+ case 1:
+ ua->auto_display_messages = 0;
+ break;
+ default:
+ bsendmsg(ua, _("ON or OFF keyword missing.\n"));
+ break;
}
return 1;
}
* list media - list media for given pool (deprecated)
* list volumes - list Volumes
* list clients - list clients
+ * list nextvol job=xx - list the next vol to be used by job
+ * list nextvolume job=xx - same as above.
*
*/
/* Do long or full listing */
-int llistcmd(UAContext *ua, char *cmd)
+int llist_cmd(UAContext *ua, char *cmd)
{
- return do_listcmd(ua, cmd, VERT_LIST);
+ return do_list_cmd(ua, cmd, VERT_LIST);
}
/* Do short or summary listing */
-int listcmd(UAContext *ua, char *cmd)
+int list_cmd(UAContext *ua, char *cmd)
{
- return do_listcmd(ua, cmd, HORZ_LIST);
+ return do_list_cmd(ua, cmd, HORZ_LIST);
}
-static int do_listcmd(UAContext *ua, char *cmd, e_list_type llist)
+static int do_list_cmd(UAContext *ua, char *cmd, e_list_type llist)
{
POOLMEM *VolumeName;
int jobid, n;
bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
return 1;
+ /* List next volume */
+ } else if (strcasecmp(ua->argk[i], _("nextvol")) == 0 ||
+ strcasecmp(ua->argk[i], _("nextvolume")) == 0) {
+ JOB *job;
+ JCR *jcr = ua->jcr;
+ i = find_arg_with_value(ua, "job");
+ if (i <= 0) {
+ if ((job = select_job_resource(ua)) == NULL) {
+ return 1;
+ }
+ } else {
+ job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
+ if (!job) {
+ Jmsg(jcr, M_ERROR, 0, _("%s is not a job name.\n"), ua->argv[i]);
+ if ((job = select_job_resource(ua)) == NULL) {
+ return 1;
+ }
+ }
+ }
+ if (!complete_jcr_for_job(jcr, job, NULL)) {
+ return 1;
+ }
+
+ if (!find_next_volume_for_append(jcr, &mr, 0)) {
+ bsendmsg(ua, "Could not find next Volume\n");
+ db_close_database(jcr, jcr->db);
+ jcr->db = NULL;
+ return 1;
+ } else {
+ bsendmsg(ua, "The next Volume to be used by Job \"%s\" will be %s\n",
+ job->hdr.name, mr.VolumeName);
+ }
+ db_close_database(jcr, jcr->db);
+ jcr->db = NULL;
} else {
bsendmsg(ua, _("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
}
return 1;
}
+/*
+ * Fill in the remaining fields of the jcr as if it
+ * is going to run the job.
+ */
+int complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
+{
+ POOL_DBR pr;
+
+ memset(&pr, 0, sizeof(POOL_DBR));
+ set_jcr_defaults(jcr, job);
+ if (pool) {
+ jcr->pool = pool; /* override */
+ }
+ jcr->db = jcr->db=db_init_database(jcr, jcr->catalog->db_name, jcr->catalog->db_user,
+ jcr->catalog->db_password, jcr->catalog->db_address,
+ jcr->catalog->db_port, jcr->catalog->db_socket);
+ if (!jcr->db || !db_open_database(jcr, jcr->db)) {
+ Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
+ jcr->catalog->db_name);
+ if (jcr->db) {
+ Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ }
+ return 0;
+ }
+ bstrncpy(pr.Name, jcr->pool->hdr.name, sizeof(pr.Name));
+ while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
+ /* Try to create the pool */
+ if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
+ Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
+ db_strerror(jcr->db));
+ db_close_database(jcr, jcr->db);
+ jcr->db = NULL;
+ return 0;
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
+ }
+ }
+ jcr->PoolId = pr.PoolId;
+ jcr->jr.PoolId = pr.PoolId;
+ return 1;
+}
+
+
static void con_lock_release(void *arg)
{
Vw(con_lock);
char dt[MAX_TIME_LENGTH], b1[30], b2[30];
int pool_mem = FALSE;
- Dmsg0(200, "Doing status\n");
bsendmsg(ua, "%s Version: " VERSION " (" BDATE ") %s %s %s\n", my_name,
HOST_OS, DISTNAME, DISTVER);
bstrftime(dt, sizeof(dt), daemon_start_time);
static void prt_runhdr(UAContext *ua)
{
- bsendmsg(ua, _("Level Type Scheduled Name\n"));
- bsendmsg(ua, _("=================================================================\n"));
+ bsendmsg(ua, _("\nScheduled Jobs:\n"));
+ bsendmsg(ua, _("Level Type Scheduled Name Volume\n"));
+ bsendmsg(ua, _("===============================================================================\n"));
}
-static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime)
+static void prt_runtime(UAContext *ua, JOB *job, int level, time_t runtime, POOL *pool)
{
char dt[MAX_TIME_LENGTH];
-
+ bool ok = false;
+ JCR *jcr = ua->jcr;
+ MEDIA_DBR mr;
+ memset(&mr, 0, sizeof(mr));
+ if (job->JobType == JT_BACKUP) {
+ jcr->db = NULL;
+ ok = complete_jcr_for_job(jcr, job, pool);
+ if (ok) {
+ ok = find_next_volume_for_append(jcr, &mr, 0);
+ }
+ if (!ok) {
+ bstrncpy(mr.VolumeName, "*unknown*", sizeof(mr.VolumeName));
+ }
+ }
bstrftime(dt, sizeof(dt), runtime);
- bsendmsg(ua, _("%-14s %-8s %-18s %s\n"),
- level_to_str(level), job_type_to_str(job->JobType), dt, job->hdr.name);
+ bsendmsg(ua, _("%-14s %-8s %-18s %-18s %s\n"),
+ level_to_str(level), job_type_to_str(job->JobType), dt, job->hdr.name,
+ mr.VolumeName);
+ if (jcr->db) {
+ db_close_database(jcr, jcr->db);
+ jcr->db = ua->db;
+ }
+
}
/*
hdr_printed = TRUE;
prt_runhdr(ua);
}
- prt_runtime(ua, job, level, runtime);
+ prt_runtime(ua, job, level, runtime, run->pool);
found = TRUE;
break;
}
hdr_printed = TRUE;
prt_runhdr(ua);
}
- prt_runtime(ua, job, level, runtime);
+ prt_runtime(ua, job, level, runtime, run->pool);
}
}
} /* end for loop over runs */
/* wait for worker child to exit */
for ( ;; ) {
Dmsg2(200, "Wait for %d opt=%d\n", bpipe->worker_pid, wait_option);
- wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
- if (wpid == bpipe->worker_pid || (wpid == -1 && errno != EINTR)) {
+ do {
+ wpid = waitpid(bpipe->worker_pid, &chldstatus, wait_option);
+ } while (wpid == -1 && (errno == EINTR || errno == EAGAIN));
+ if (wpid == bpipe->worker_pid || wpid == -1) {
Dmsg3(200, "Got break wpid=%d status=%d ERR=%s\n", wpid, chldstatus,
wpid==-1?strerror(errno):"none");
break;
* Bacula's implementation of fgets(). The difference is that it handles
* being interrupted by a signal (e.g. a SIGCHLD).
*/
-#undef bfgets
+#undef fgetc
char *bfgets(char *s, int size, FILE *fd)
{
char *p = s;
*/
void scan_to_eol(LEX *lc)
{
- Dmsg0(150, "start scan to eof\n");
+ Dmsg0(900, "start scan to eof\n");
while (lex_get_token(lc, T_ALL) != T_EOL)
{ }
- Dmsg0(150, "done scan to eof\n");
+ Dmsg0(900, "done scan to eof\n");
}
{
LEX *of;
- Dmsg1(40, "Close lex file: %s\n", lf->fname);
+ Dmsg1(900, "Close lex file: %s\n", lf->fname);
if (lf == NULL) {
Emsg0(M_ABORT, 0, "Close of NULL file\n");
}
of = lf->next;
fclose(lf->fd);
- Dmsg1(49, "Close cfg file %s\n", lf->fname);
+ Dmsg1(900, "Close cfg file %s\n", lf->fname);
free(lf->fname);
if (of) {
of->options = lf->options; /* preserve options */
memcpy(lf, of, sizeof(LEX));
- Dmsg1(49, "Restart scan of cfg file %s\n", of->fname);
+ Dmsg1(900, "Restart scan of cfg file %s\n", of->fname);
} else {
of = lf;
lf = NULL;
Emsg2(M_ERROR_TERM, 0, _("Cannot open config file %s: %s\n"),
fname, strerror(errno));
}
- Dmsg1(49, "Open config file: %s\n", fname);
+ Dmsg1(900, "Open config file: %s\n", fname);
nf = (LEX *)malloc(sizeof(LEX));
if (lf) {
memcpy(nf, lf, sizeof(LEX));
} else {
lf->scan_error = s_err;
}
- Dmsg1(49, "Return lex=%x\n", lf);
+ Dmsg1(900, "Return lex=%x\n", lf);
return lf;
}
int token = T_NONE;
int esc_next = FALSE;
- Dmsg0(290, "enter lex_get_token\n");
+ Dmsg0(900, "enter lex_get_token\n");
while (token == T_NONE) {
ch = lex_get_char(lf);
switch (lf->state) {
case lex_none:
- Dmsg2(290, "Lex state lex_none ch=%d,%x\n", ch, ch);
+ Dmsg2(900, "Lex state lex_none ch=%d,%x\n", ch, ch);
if (B_ISSPACE(ch))
break;
if (B_ISALPHA(ch)) {
begin_str(lf, ch);
break;
}
- Dmsg0(290, "Enter lex_none switch\n");
+ Dmsg0(900, "Enter lex_none switch\n");
switch (ch) {
case L_EOF:
token = T_EOF;
- Dmsg0(290, "got L_EOF set token=T_EOF\n");
+ Dmsg0(900, "got L_EOF set token=T_EOF\n");
break;
case '#':
lf->state = lex_comment;
token = T_EOL; /* treat ; like EOL */
break;
case L_EOL:
- Dmsg0(290, "got L_EOL set token=T_EOL\n");
+ Dmsg0(900, "got L_EOL set token=T_EOL\n");
token = T_EOL;
break;
case '@':
}
break;
case lex_comment:
- Dmsg1(290, "Lex state lex_comment ch=%x\n", ch);
+ Dmsg1(900, "Lex state lex_comment ch=%x\n", ch);
if (ch == L_EOL) {
lf->state = lex_none;
token = T_EOL;
}
break;
case lex_number:
- Dmsg2(290, "Lex state lex_number ch=%x %c\n", ch, ch);
+ Dmsg2(900, "Lex state lex_number ch=%x %c\n", ch, ch);
if (ch == L_EOF) {
token = T_ERROR;
break;
token = T_ERROR;
break;
}
- Dmsg1(290, "Lex state lex_ip_addr ch=%x\n", ch);
+ Dmsg1(900, "Lex state lex_ip_addr ch=%x\n", ch);
break;
case lex_string:
- Dmsg1(290, "Lex state lex_string ch=%x\n", ch);
+ Dmsg1(900, "Lex state lex_string ch=%x\n", ch);
if (ch == L_EOF) {
token = T_ERROR;
break;
add_str(lf, ch);
break;
case lex_identifier:
- Dmsg2(290, "Lex state lex_identifier ch=%x %c\n", ch, ch);
+ Dmsg2(900, "Lex state lex_identifier ch=%x %c\n", ch, ch);
if (B_ISALPHA(ch)) {
add_str(lf, ch);
break;
add_str(lf, ch);
break;
case lex_quoted_string:
- Dmsg2(290, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
+ Dmsg2(900, "Lex state lex_quoted_string ch=%x %c\n", ch, ch);
if (ch == L_EOF) {
token = T_ERROR;
break;
add_str(lf, ch);
break;
}
- Dmsg4(290, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
+ Dmsg4(900, "ch=%d state=%s token=%s %c\n", ch, lex_state_to_str(lf->state),
lex_tok_to_str(token), ch);
}
- Dmsg2(290, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
+ Dmsg2(900, "lex returning: line %d token: %s\n", lf->line_no, lex_tok_to_str(token));
lf->token = token;
/*
break;
case T_INT64:
- Dmsg2(400, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
+ Dmsg2(900, "int64=:%s: %f\n", lf->str, strtod(lf->str, NULL));
if (token != T_NUMBER || !is_a_number(lf->str)) {
scan_err2(lf, "expected an integer number, got %s: %s",
lex_tok_to_str(token), lf->str);
#undef VERSION
#define VERSION "1.32"
#define VSTRING "1"
-#define BDATE "12 Sep 2003"
-#define LSMDATE "12Sep03"
+#define BDATE "16 Sep 2003"
+#define LSMDATE "16Sep03"
/* Debug flags */
#undef DEBUG