2002-xx-xx Version 1.26 (xxOct02)
-General:
+General: From kes25Sep02
+- Added means to bind servers to specific address.
+- Documentation
+
+Changes submitted this submission:
+- Added DirAddress, FDAddress, and SDAddress records to the corresponding
+ resources that allow the server to bind to a specific address
+ rather than any address. This security improvement was suggested by
+ a user -- thank you.
+- Eliminated deprecated "Address" record from all sample Storage resources.
+- Made quite a lot of improvements to the bscan program. Much more
+ to do. Aside from details, it is able to recreate a database
+ from which you can do a restore.
+- The s option is not accepted on all versions of ar, so replaced it
+ by an explicit ranlib call.
+- Fixed a bug that caused the Director to crash if you rudely bring
+ down the console program in the middle of an SQL command.
+- Fixed a bug (missing break) that caused scheduled Admin jobs to
+ be listed as "Unknown type".
+- Removed old code from Storage daemon that used a separate FD port.
+
+General: From kes14Sep02
- Better key generation on non OpenSSL systems.
- 64 bit file address support if available.
- Implement autochanger for reading
@echo " "
libsql.a: $(LIBOBJS)
- $(AR) rcs $@ $(LIBOBJS)
+ $(AR) rc $@ $(LIBOBJS)
+ $(RANLIB) $@
cats: $(SVROBJS) ../findlib/libfind.a
$(CC) $(LDFLAGS) -L../findlib -L../lib -o $@ $(SVROBJS) $(LIBS) $(DB_LIBS) -lfind -lbac
extern void term_ua_server();
extern int do_backup(JCR *jcr);
extern void backup_cleanup(void);
-extern void start_UA_server(int port);
+extern void start_UA_server(char *addr, int port);
extern void run_job(JCR *jcr);
extern void init_job_server(int max_workers);
4 /* UA */ + 4 /* sched+watchdog+jobsvr+misc */);
Dmsg0(200, "Start UA server\n");
- start_UA_server(director->DIRport);
+ start_UA_server(director->DIRaddr, director->DIRport);
start_watchdog(); /* start network watchdog thread */
{"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
{"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
{"dirport", store_pint, ITEM(res_dir.DIRport), 0, ITEM_DEFAULT, 9101},
+ {"diraddress", store_str, ITEM(res_dir.DIRaddr), 0, 0, 0},
{"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
{"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
{"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
switch (type) {
case R_DIRECTOR:
- if (res->res_dir.working_directory)
+ if (res->res_dir.working_directory) {
free(res->res_dir.working_directory);
- if (res->res_dir.pid_directory)
+ }
+ if (res->res_dir.pid_directory) {
free(res->res_dir.pid_directory);
- if (res->res_dir.subsys_directory)
+ }
+ if (res->res_dir.subsys_directory) {
free(res->res_dir.subsys_directory);
- if (res->res_dir.password)
+ }
+ if (res->res_dir.password) {
free(res->res_dir.password);
- if (res->res_dir.query_file)
+ }
+ if (res->res_dir.query_file) {
free(res->res_dir.query_file);
+ }
+ if (res->res_dir.DIRaddr) {
+ free(res->res_dir.DIRaddr);
+ }
break;
case R_CLIENT:
- if (res->res_client.address)
+ if (res->res_client.address) {
free(res->res_client.address);
- if (res->res_client.password)
+ }
+ if (res->res_client.password) {
free(res->res_client.password);
+ }
break;
case R_STORAGE:
if (res->res_store.address)
struct s_res_dir {
RES hdr;
int DIRport; /* where we listen -- UA port server port */
+ char *DIRaddr; /* bind address */
char *password; /* Password for UA access */
char *query_file; /* SQL query file */
char *working_directory; /* WorkingDirectory */
extern int do_restore(JCR *jcr);
extern int do_verify(JCR *jcr);
extern void backup_cleanup(void);
-extern void start_UA_server(int port);
/* Queue of jobs to be run */
static workq_t job_wq; /* our job work queue */
bnet_fsend(sock, "%s", prompt);
bnet_sig(sock, BNET_PROMPT); /* request more input */
for ( ;; ) {
- if (bnet_recv(sock) < 0) {
+ if (bnet_recv(sock) <= 0) {
return 0;
}
ua->cmd = check_pool_memory_size(ua->cmd, sock->msglen+1);
static int started = FALSE;
static workq_t ua_workq;
+struct s_addr_port {
+ char *addr;
+ int port;
+};
+
/* Called here by Director daemon to start UA (user agent)
* command thread. This routine creates the thread and then
* returns.
*/
-void start_UA_server(int UA_port)
+void start_UA_server(char *UA_addr, int UA_port)
{
pthread_t thid;
int status;
+ static struct s_addr_port arg;
- if ((status=pthread_create(&thid, NULL, connect_thread, (void *)UA_port)) != 0) {
+ arg.port = UA_port;
+ arg.addr = UA_addr;
+ if ((status=pthread_create(&thid, NULL, connect_thread, (void *)&arg)) != 0) {
Emsg1(M_ABORT, 0, _("Cannot create UA thread: %s\n"), strerror(status));
}
started = TRUE;
static void *connect_thread(void *arg)
{
- int UA_port = (int)arg;
+ struct s_addr_port *UA = (struct s_addr_port *)arg;
pthread_detach(pthread_self());
/* ****FIXME**** put # 5 on config parameter */
- bnet_thread_server(UA_port, 5, &ua_workq, handle_UA_client_request);
+ bnet_thread_server(UA->addr, UA->port, 5, &ua_workq, handle_UA_client_request);
return NULL;
}
/* Become server, and handle requests */
Dmsg1(10, "filed: listening on port %d\n", me->FDport);
- bnet_thread_server(me->FDport, me->MaxConcurrentJobs, &dir_workq, handle_client_request);
+ bnet_thread_server(me->FDaddr, me->FDport, me->MaxConcurrentJobs,
+ &dir_workq, handle_client_request);
exit(0); /* should never get here */
}
{"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
{"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
{"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
+ {"fdaddress", store_str, ITEM(res_client.FDaddr), 0, 0, 0},
{"workingdirectory", store_dir, ITEM(res_client.working_directory), 0, ITEM_REQUIRED, 0},
{"piddirectory", store_dir, ITEM(res_client.pid_directory), 0, ITEM_REQUIRED, 0},
{"subsysdirectory", store_dir, ITEM(res_client.subsys_directory), 0, ITEM_REQUIRED, 0},
switch (type) {
case R_DIRECTOR:
- if (res->res_dir.password)
+ if (res->res_dir.password) {
free(res->res_dir.password);
- if (res->res_dir.address)
+ }
+ if (res->res_dir.address) {
free(res->res_dir.address);
+ }
break;
case R_CLIENT:
- if (res->res_client.working_directory)
+ if (res->res_client.working_directory) {
free(res->res_client.working_directory);
- if (res->res_client.pid_directory)
+ }
+ if (res->res_client.pid_directory) {
free(res->res_client.pid_directory);
- if (res->res_client.subsys_directory)
+ }
+ if (res->res_client.subsys_directory) {
free(res->res_client.subsys_directory);
+ }
+ if (res->res_client.FDaddr) {
+ free(res->res_client.FDaddr);
+ }
break;
case R_MSGS:
if (res->res_msgs.mail_cmd)
/*
* Resource codes -- they must be sequential for indexing
*/
-#define R_FIRST 1001
+#define R_FIRST 1001
-#define R_DIRECTOR 1001
-#define R_CLIENT 1002
-#define R_MSGS 1003
+#define R_DIRECTOR 1001
+#define R_CLIENT 1002
+#define R_MSGS 1003
-#define R_LAST R_MSGS
+#define R_LAST R_MSGS
/*
* Some resource attributes
*/
-#define R_NAME 1020
-#define R_ADDRESS 1021
-#define R_PASSWORD 1022
-#define R_TYPE 1023
+#define R_NAME 1020
+#define R_ADDRESS 1021
+#define R_PASSWORD 1022
+#define R_TYPE 1023
/* Definition of the contents of each Resource */
struct s_res_dir {
- RES hdr;
- char *password; /* Director password */
- char *address; /* Director address or zero */
+ RES hdr;
+ char *password; /* Director password */
+ char *address; /* Director address or zero */
};
typedef struct s_res_dir DIRRES;
struct s_res_client {
- RES hdr;
- int FDport; /* where we listen for Directors */
+ RES hdr;
+ int FDport; /* where we listen for Directors */
+ char *FDaddr; /* bind address */
char *working_directory;
char *pid_directory;
char *subsys_directory;
* resource structure definitions.
*/
union u_res {
- struct s_res_dir res_dir;
- struct s_res_client res_client;
- struct s_res_msgs res_msgs;
+ struct s_res_dir res_dir;
+ struct s_res_client res_client;
+ struct s_res_msgs res_msgs;
RES hdr;
};
@echo " "
libfind.a: $(LIBOBJS)
- $(RMF) libfind.a
- $(AR) crs $@ $(LIBOBJS)
+ $(RMF) $@
+ $(AR) cr $@ $(LIBOBJS)
+ $(RANLIB) $@
Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
cd $(topdir) \
char *RestoreBootstrap; /* Bootstrap file to restore */
char *sd_auth_key; /* SD auth key */
MSGS *jcr_msgs; /* Copy of message resource -- actually used */
+ uint32_t ClientId; /* Client associated with Job */
/* Daemon specific part of JCR */
/* This should be empty in the library */
int SDJobStatus; /* Storage Job Status */
int mode; /* manual/auto run */
B_DB *db; /* database pointer */
- int MediaId; /* DB record IDs associated with this job */
- int ClientId; /* Client associated with file */
+ uint32_t MediaId; /* DB record IDs associated with this job */
uint32_t PoolId; /* Pool record id */
FileId_t FileId; /* Last file id inserted */
uint32_t FileIndex; /* Last FileIndex processed */
int fn_printed; /* printed filename */
POOLMEM *stime; /* start time for incremental/differential */
JOB_DBR jr; /* Job record in Database */
- int RestoreJobId; /* Id specified by UA */
+ uint32_t RestoreJobId; /* Id specified by UA */
char *RestoreWhere; /* Where to restore the files */
#endif /* DIRECTOR_DAEMON */
DEV_RECORD rec; /* Read/Write record */
long Ticket; /* ticket for this job */
uint32_t VolFirstFile; /* First file index this Volume */
+ uint32_t FileIndex; /* Current File Index */
uint32_t start_block; /* Start write block */
uint32_t start_file; /* Start write file */
uint32_t end_block; /* Ending block written */
extern void free_jcr(JCR *jcr);
extern void free_locked_jcr(JCR *jcr);
extern JCR *get_jcr_by_id(uint32_t JobId);
+extern JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime);
extern JCR *get_jcr_by_partial_name(char *Job);
extern JCR *get_jcr_by_full_name(char *Job);
extern JCR *get_next_jcr(JCR *jcr);
@echo " "
libbac.a: $(LIBOBJS)
- $(AR) rcs $@ $(LIBOBJS)
+ $(AR) rc $@ $(LIBOBJS)
+ $(RANLIB) $@
Makefile: $(srcdir)/Makefile.in $(topdir)/config.status
/* Become Threaded Network Server */
void
-bnet_thread_server(int port, int max_clients, workq_t *client_wq,
+bnet_thread_server(char *bind_addr, int port, int max_clients, workq_t *client_wq,
void handle_client_request(void *bsock))
{
int newsockfd, sockfd, stat;
socklen_t clilen;
struct sockaddr_in cli_addr; /* client's address */
struct sockaddr_in serv_addr; /* our address */
+ struct in_addr bind_ip; /* address to bind to */
int tlog;
fd_set ready, sockset;
int turnon = 1;
/*
* Bind our local address so that the client can send to us.
*/
- bzero((char *) &serv_addr, sizeof(serv_addr));
+ bind_ip.s_addr = htonl(INADDR_ANY);
+ if (bind_addr && bind_addr[0]) {
+ if (inet_pton(AF_INET, bind_addr, &bind_ip) <= 0) {
+ Emsg1(M_WARNING, 0, _("Invalid bind address: %s, using INADDR_ANY\n"),
+ bind_addr);
+ bind_ip.s_addr = htonl(INADDR_ANY);
+ }
+ }
+ memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serv_addr.sin_addr.s_addr = bind_ip.s_addr;
serv_addr.sin_port = htons(port);
int tmax = 30 * (60 / 5); /* wait 30 minutes max */
return jcr;
}
+/*
+ * Given a SessionId and SessionTime, find the JCR
+ * Returns: jcr on success
+ * NULL on failure
+ */
+JCR *get_jcr_by_session(uint32_t SessionId, uint32_t SessionTime)
+{
+ JCR *jcr;
+
+ P(mutex);
+ for (jcr = jobs; jcr; jcr=jcr->next) {
+ if (jcr->VolSessionId == SessionId &&
+ jcr->VolSessionTime == SessionTime) {
+ jcr->use_count++;
+ Dmsg1(200, "Increment jcr use_count=%d\n", jcr->use_count);
+ break;
+ }
+ }
+ V(mutex);
+ return jcr;
+}
/*
*/
/* base64.c */
-void base64_init (void);
-int to_base64 (intmax_t value, char *where);
-int from_base64 (intmax_t *value, char *where);
-void encode_stat (char *buf, struct stat *statp);
-void decode_stat (char *buf, struct stat *statp);
-int bin_to_base64 (char *buf, char *bin, int len);
+void base64_init (void);
+int to_base64 (intmax_t value, char *where);
+int from_base64 (intmax_t *value, char *where);
+void encode_stat (char *buf, struct stat *statp);
+void decode_stat (char *buf, struct stat *statp);
+int bin_to_base64 (char *buf, char *bin, int len);
/* bmisc.c */
-char *bstrncpy (char *dest, char *src, int maxlen);
-void *b_malloc (char *file, int line, size_t size);
+char *bstrncpy (char *dest, char *src, int maxlen);
+void *b_malloc (char *file, int line, size_t size);
#ifndef DEBUG
-void *bmalloc (size_t size);
+void *bmalloc (size_t size);
#endif
-void *brealloc (void *buf, size_t size);
-void *bcalloc (size_t size1, size_t size2);
-int bsnprintf (char *str, size_t size, const char *format, ...);
-int bvsnprintf (char *str, size_t size, const char *format, va_list ap);
-int pool_sprintf (char *pool_buf, char *fmt, ...);
-void create_pid_file (char *dir, char *progname, int port);
-int delete_pid_file (char *dir, char *progname, int port);
+void *brealloc (void *buf, size_t size);
+void *bcalloc (size_t size1, size_t size2);
+int bsnprintf (char *str, size_t size, const char *format, ...);
+int bvsnprintf (char *str, size_t size, const char *format, va_list ap);
+int pool_sprintf (char *pool_buf, char *fmt, ...);
+void create_pid_file (char *dir, char *progname, int port);
+int delete_pid_file (char *dir, char *progname, int port);
#ifndef HAVE_STRERROR_R
-int strerror_r (int errnum, char *buf, size_t bufsiz);
+int strerror_r (int errnum, char *buf, size_t bufsiz);
#endif
/* bnet.c */
-int32_t bnet_recv (BSOCK *bsock);
-int bnet_send (BSOCK *bsock);
-int bnet_fsend (BSOCK *bs, char *fmt, ...);
-int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw);
-int bnet_sig (BSOCK *bs, int sig);
-BSOCK * bnet_connect (void *jcr, int retry_interval,
- int max_retry_time, char *name, char *host, char *service,
- int port, int verbose);
-int bnet_wait_data (BSOCK *bsock, int sec);
-void bnet_close (BSOCK *bsock);
-BSOCK * init_bsock (void *jcr, int sockfd, char *who, char *ip, int port);
-BSOCK * dup_bsock (BSOCK *bsock);
-void term_bsock (BSOCK *bsock);
-char * bnet_strerror (BSOCK *bsock);
-char * bnet_sig_to_ascii (BSOCK *bsock);
-int bnet_wait_data (BSOCK *bsock, int sec);
-int bnet_despool (BSOCK *bsock);
+int32_t bnet_recv (BSOCK *bsock);
+int bnet_send (BSOCK *bsock);
+int bnet_fsend (BSOCK *bs, char *fmt, ...);
+int bnet_set_buffer_size (BSOCK *bs, uint32_t size, int rw);
+int bnet_sig (BSOCK *bs, int sig);
+BSOCK * bnet_connect (void *jcr, int retry_interval,
+ int max_retry_time, char *name, char *host, char *service,
+ int port, int verbose);
+int bnet_wait_data (BSOCK *bsock, int sec);
+void bnet_close (BSOCK *bsock);
+BSOCK * init_bsock (void *jcr, int sockfd, char *who, char *ip, int port);
+BSOCK * dup_bsock (BSOCK *bsock);
+void term_bsock (BSOCK *bsock);
+char * bnet_strerror (BSOCK *bsock);
+char * bnet_sig_to_ascii (BSOCK *bsock);
+int bnet_wait_data (BSOCK *bsock, int sec);
+int bnet_despool (BSOCK *bsock);
/* cram-md5.c */
int cram_md5_get_auth(BSOCK *bs, char *password);
int cram_md5_auth(BSOCK *bs, char *password);
void hmac_md5(uint8_t* text, int text_len, uint8_t* key,
- int key_len, uint8_t *hmac);
+ int key_len, uint8_t *hmac);
/* create_file.c */
int create_file(void *jcr, char *fname, char *ofile, char *lname,
- int type, struct stat *statp, int *ofd);
+ int type, struct stat *statp, int *ofd);
int set_statp(void *jcr, char *fname, char *ofile, char *lname, int type,
- struct stat *statp);
+ struct stat *statp);
/* crc32.c */
uint32_t bcrc32(uint8_t *buf, int len);
/* daemon.c */
-void daemon_start ();
+void daemon_start ();
/* lex.c */
-LEX * lex_close_file (LEX *lf);
-LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error);
-int lex_get_char (LEX *lf);
-void lex_unget_char (LEX *lf);
-char * lex_tok_to_str (int token);
-int lex_get_token (LEX *lf, int expect);
+LEX * lex_close_file (LEX *lf);
+LEX * lex_open_file (LEX *lf, char *fname, LEX_ERROR_HANDLER *scan_error);
+int lex_get_char (LEX *lf);
+void lex_unget_char (LEX *lf);
+char * lex_tok_to_str (int token);
+int lex_get_token (LEX *lf, int expect);
/* makepath.c */
int make_path(
- void *jcr,
- const char *argpath,
- int mode,
- int parent_mode,
- uid_t owner,
- gid_t group,
- int preserve_existing,
- char *verbose_fmt_string);
+ void *jcr,
+ const char *argpath,
+ int mode,
+ int parent_mode,
+ uid_t owner,
+ gid_t group,
+ int preserve_existing,
+ char *verbose_fmt_string);
/* message.c */
-void my_name_is (int argc, char *argv[], char *name);
-void init_msg (void *jcr, MSGS *msg);
-void term_msg (void);
-void close_msg (void *jcr);
-void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code);
-void rem_msg_dest (MSGS *msg, int dest, int type, char *where);
-void Jmsg (void *jcr, int type, int level, char *fmt, ...);
-void dispatch_message (void *jcr, int type, int level, char *buf);
-void init_console_msg (char *wd);
-void free_msgs_res (MSGS *msgs);
-int open_spool_file (void *jcr, BSOCK *bs);
-int close_spool_file (void *vjcr, BSOCK *bs);
+void my_name_is (int argc, char *argv[], char *name);
+void init_msg (void *jcr, MSGS *msg);
+void term_msg (void);
+void close_msg (void *jcr);
+void add_msg_dest (MSGS *msg, int dest, int type, char *where, char *dest_code);
+void rem_msg_dest (MSGS *msg, int dest, int type, char *where);
+void Jmsg (void *jcr, int type, int level, char *fmt, ...);
+void dispatch_message (void *jcr, int type, int level, char *buf);
+void init_console_msg (char *wd);
+void free_msgs_res (MSGS *msgs);
+int open_spool_file (void *jcr, BSOCK *bs);
+int close_spool_file (void *vjcr, BSOCK *bs);
/* bnet_server.c */
-void bnet_thread_server(int port, int max_clients, workq_t *client_wq,
- void handle_client_request(void *bsock));
-void bnet_server (int port, void handle_client_request(BSOCK *bsock));
-int net_connect (int port);
-BSOCK * bnet_bind (int port);
-BSOCK * bnet_accept (BSOCK *bsock, char *who);
+void bnet_thread_server(char *bind_addr, int port, int max_clients, workq_t *client_wq,
+ void handle_client_request(void *bsock));
+void bnet_server (int port, void handle_client_request(BSOCK *bsock));
+int net_connect (int port);
+BSOCK * bnet_bind (int port);
+BSOCK * bnet_accept (BSOCK *bsock, char *who);
/* signal.c */
-void init_signals (void terminate(int sig));
-void init_stack_dump (void);
+void init_signals (void terminate(int sig));
+void init_stack_dump (void);
/* util.c */
-void lcase (char *str);
-void bash_spaces (char *str);
-void unbash_spaces (char *str);
-void strip_trailing_junk (char *str);
-void strip_trailing_slashes (char *dir);
-int skip_spaces (char **msg);
-int skip_nonspaces (char **msg);
-int fstrsch (char *a, char *b);
-char * encode_time (time_t time, char *buf);
-char * encode_mode (mode_t mode, char *buf);
-char * edit_uint64_with_commas (uint64_t val, char *buf);
-char * add_commas (char *val, char *buf);
-char * edit_uint64 (uint64_t val, char *buf);
-int do_shell_expansion (char *name);
-int is_a_number (const char *num);
-int string_to_btime (char *str, btime_t *value);
-char *edit_btime (btime_t val, char *buf);
-void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen);
-void pm_strcat (POOLMEM **pm, char *str);
-void pm_strcpy (POOLMEM **pm, char *str);
-int run_program (char *prog, int wait, POOLMEM *results);
-char * job_type_to_str (int type);
-char * job_status_to_str (int stat);
-char * job_level_to_str (int level);
-void makeSessionKey (char *key, char *seed, int mode);
+void lcase (char *str);
+void bash_spaces (char *str);
+void unbash_spaces (char *str);
+void strip_trailing_junk (char *str);
+void strip_trailing_slashes (char *dir);
+int skip_spaces (char **msg);
+int skip_nonspaces (char **msg);
+int fstrsch (char *a, char *b);
+char * encode_time (time_t time, char *buf);
+char * encode_mode (mode_t mode, char *buf);
+char * edit_uint64_with_commas (uint64_t val, char *buf);
+char * add_commas (char *val, char *buf);
+char * edit_uint64 (uint64_t val, char *buf);
+int do_shell_expansion (char *name);
+int is_a_number (const char *num);
+int string_to_btime (char *str, btime_t *value);
+char *edit_btime (btime_t val, char *buf);
+void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen);
+void pm_strcat (POOLMEM **pm, char *str);
+void pm_strcpy (POOLMEM **pm, char *str);
+int run_program (char *prog, int wait, POOLMEM *results);
+char * job_type_to_str (int type);
+char * job_status_to_str (int stat);
+char * job_level_to_str (int level);
+void makeSessionKey (char *key, char *seed, int mode);
break;
case JT_ADMIN:
str = _("Admin");
+ break;
default:
str = _("Unknown Type");
break;
Storage { # definition of myself
Name = @hostname@-sd
- Address = @hostname@
SDPort = @sd_port@ # Director's port
WorkingDirectory = "@working_dir@"
Pid Directory = "@piddir@"
/* Forward referenced functions */
static void do_scan(char *fname);
static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
-static void create_file_attributes_record(B_DB *db, char *fname, char *lname, int type,
+static int create_file_attributes_record(B_DB *db, char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec);
-static void create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
-static void create_pool_record(B_DB *db, POOL_DBR *pr);
-static void create_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *label);
-static void update_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
+static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl);
+static int create_pool_record(B_DB *db, POOL_DBR *pr);
+static int create_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *label, DEV_RECORD *rec);
+static int update_job_record(B_DB *db, JOB_DBR *mr, SESSION_LABEL *elabel,
DEV_RECORD *rec);
-static void create_client_record(B_DB *db, CLIENT_DBR *cr);
-static void create_fileset_record(B_DB *db, FILESET_DBR *fsr);
-static void create_jobmedia_record(B_DB *db, JOBMEDIA_DBR *jmr, SESSION_LABEL *elabel);
+static int create_client_record(B_DB *db, CLIENT_DBR *cr);
+static int create_fileset_record(B_DB *db, FILESET_DBR *fsr);
+static int create_jobmedia_record(B_DB *db, JCR *jcr);
+static void create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId);
/* Global variables */
static DEVICE *dev = NULL;
static B_DB *db;
-static JCR *jcr;
+static JCR *jcr; /* jcr for bscan */
+static JCR *jobjcr; /* jcr for simulating running job */
static BSR *bsr;
static struct stat statp;
static int type;
static POOL_DBR pr;
static JOB_DBR jr;
static CLIENT_DBR cr;
-static JOBMEDIA_DBR jmr;
static FILESET_DBR fsr;
static ATTR_DBR ar;
static SESSION_LABEL label;
static SESSION_LABEL elabel;
-static uint32_t FirstIndex = 0;
-static uint32_t LastIndex = 0;
static char *db_name = "bacula";
static char *db_user = "bacula";
static void usage()
{
- fprintf(stderr,
+ fprintf(stderr, _(
"\nVersion: " VERSION " (" DATE ")\n\n"
"Usage: bscan [-d debug_level] <bacula-archive>\n"
" -b bootstrap specify a bootstrap file\n"
" -s synchronize or store in database\n"
" -v verbose\n"
" -w dir specify working directory (default /tmp)\n"
-" -? print this message\n\n");
+" -? print this message\n\n"));
exit(1);
}
init_msg(NULL, NULL);
- while ((ch = getopt(argc, argv, "b:d:n:p:u:vw:?")) != -1) {
+ while ((ch = getopt(argc, argv, "b:d:n:p:su:vw:?")) != -1) {
switch (ch) {
case 'b':
bsr = parse_bsr(NULL, optarg);
argv += optind;
if (argc != 1) {
- Pmsg0(0, "Wrong number of arguments: \n");
+ Pmsg0(0, _("Wrong number of arguments: \n"));
usage();
}
jcr = setup_jcr("bscan", argv[0], bsr);
if ((db=db_init_database(NULL, db_name, db_user, db_password)) == NULL) {
- Emsg0(M_ABORT, 0, "Could not init Bacula database\n");
+ Emsg0(M_ERROR_TERM, 0, _("Could not init Bacula database\n"));
}
if (!db_open_database(db)) {
- Emsg0(M_ABORT, 0, db_strerror(db));
+ Emsg0(M_ERROR_TERM, 0, db_strerror(db));
}
Dmsg0(200, "Database opened\n");
-
+ if (verbose) {
+ Pmsg2(000, _("Using Database: %s, User: %s\n"), db_name, db_user);
+ }
do_scan(argv[0]);
lname = get_pool_memory(PM_FNAME);
memset(&ar, 0, sizeof(ar));
- memset(&mr, 0, sizeof(mr));
memset(&pr, 0, sizeof(pr));
memset(&jr, 0, sizeof(jr));
memset(&cr, 0, sizeof(cr));
- memset(&jmr, 0, sizeof(jmr));
memset(&fsr, 0, sizeof(fsr));
+ detach_jcr_from_device(dev, jcr);
+
read_records(jcr, dev, record_cb, mount_next_read_volume);
release_device(jcr, dev);
/* Check Pool info */
strcpy(pr.Name, dev->VolHdr.PoolName);
strcpy(pr.PoolType, dev->VolHdr.PoolType);
- if (!db_get_pool_record(db, &pr)) {
+ if (db_get_pool_record(db, &pr)) {
+ if (verbose) {
+ Pmsg1(000, "Pool record for %s found in DB.\n", pr.Name);
+ }
+ } else {
Pmsg1(000, "VOL_LABEL: Pool record not found for Pool: %s\n",
pr.Name);
create_pool_record(db, &pr);
- return;
- } else if (verbose) {
- Pmsg1(000, "Pool record for %s found in DB.\n", pr.Name);
}
if (strcmp(pr.PoolType, dev->VolHdr.PoolType) != 0) {
Pmsg2(000, "VOL_LABEL: PoolType mismatch. DB=%s Vol=%s\n",
}
/* Check Media Info */
+ memset(&mr, 0, sizeof(mr));
strcpy(mr.VolumeName, dev->VolHdr.VolName);
mr.PoolId = pr.PoolId;
- if (!db_get_media_record(db, &mr)) {
+ if (db_get_media_record(db, &mr)) {
+ if (verbose) {
+ Pmsg1(000, "Media record for %s found in DB.\n", mr.VolumeName);
+ }
+ } else {
Pmsg1(000, "VOL_LABEL: Media record not found for Volume: %s\n",
mr.VolumeName);
strcpy(mr.MediaType, dev->VolHdr.MediaType);
create_media_record(db, &mr, &dev->VolHdr);
- return;
- } else if (verbose) {
- Pmsg1(000, "Media record for %s found in DB.\n", mr.VolumeName);
}
if (strcmp(mr.MediaType, dev->VolHdr.MediaType) != 0) {
Pmsg2(000, "VOL_LABEL: MediaType mismatch. DB=%s Vol=%s\n",
} else if (verbose) {
Pmsg1(000, "Media type \"%s\" is OK.\n", mr.MediaType);
}
+ /* Reset some JCR variables */
+ for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+ mjcr->VolFirstFile = mjcr->FileIndex = 0;
+ mjcr->start_block = mjcr->end_block = 0;
+ mjcr->start_file = mjcr->end_file = 0;
+ }
+
Pmsg1(000, "VOL_LABEL: OK for Volume: %s\n", mr.VolumeName);
break;
case SOS_LABEL:
unser_session_label(&label, rec);
- FirstIndex = LastIndex = 0;
memset(&jr, 0, sizeof(jr));
jr.JobId = label.JobId;
- if (!db_get_job_record(db, &jr)) {
+ if (db_get_job_record(db, &jr)) {
+ /* Job record already exists in DB */
+ create_jcr(&jr, rec, jr.JobId);
+ attach_jcr_to_device(dev, jobjcr);
+ if (verbose) {
+ Pmsg1(000, _("SOS_LABEL: Found Job record for JobId: %d\n"), jr.JobId);
+ }
+ } else {
+
+ /* Must create a Job record in DB */
Pmsg1(000, "SOS_LABEL: Job record not found for JobId: %d\n",
jr.JobId);
- create_job_record(db, &jr, &label);
+
+ /* Create Client record */
+ strcpy(cr.Name, label.ClientName);
+ create_client_record(db, &cr);
+ jr.ClientId = cr.ClientId;
+
+ create_job_record(db, &jr, &label, rec);
jr.PoolId = pr.PoolId;
- jr.VolSessionId = rec->VolSessionId;
- jr.VolSessionTime = rec->VolSessionTime;
- return;
+ /* Set start positions into JCR */
+ jobjcr->start_block = dev->block_num;
+ jobjcr->start_file = dev->file;
}
if (rec->VolSessionId != jr.VolSessionId) {
Pmsg3(000, "SOS_LABEL: VolSessId mismatch for JobId=%u. DB=%d Vol=%d\n",
case EOS_LABEL:
unser_session_label(&elabel, rec);
- /* Create Client record */
- strcpy(cr.Name, label.ClientName);
- create_client_record(db, &cr);
- jr.ClientId = cr.ClientId;
-
/* Create FileSet record */
strcpy(fsr.FileSet, label.FileSetName);
create_fileset_record(db, &fsr);
jr.FileSetId = fsr.FileSetId;
- /* Update Job record */
+ /* Do the final update to the Job record */
update_job_record(db, &jr, &elabel, rec);
/* Create JobMedia record */
- jmr.JobId = jr.JobId;
- jmr.MediaId = mr.MediaId;
- create_jobmedia_record(db, &jmr, &elabel);
- if (elabel.JobId != label.JobId) {
- Pmsg2(000, "EOS_LABEL: Start/End JobId mismatch. Start=%d End=%d\n",
- label.JobId, elabel.JobId);
- return;
+ jobjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!jobjcr) {
+ Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ break;
}
- if (elabel.JobFiles != jr.JobFiles) {
- Pmsg3(000, "EOS_LABEL: JobFiles mismatch for JobId=%u. DB=%d EOS=%d\n",
- elabel.JobId,
- jr.JobFiles, elabel.JobFiles);
- return;
- }
- if (elabel.JobBytes != jr.JobBytes) {
- Pmsg3(000, "EOS_LABEL: JobBytes mismatch for JobId=%u. DB=%d EOS=%d\n",
- elabel.JobId,
- jr.JobBytes, elabel.JobBytes);
- return;
- }
+
+ jobjcr->end_block = dev->block_num;
+ jobjcr->end_file = dev->file;
+ create_jobmedia_record(db, jobjcr);
+ detach_jcr_from_device(dev, jobjcr);
+ free_jcr(jobjcr);
+
Pmsg1(000, "EOS_LABEL: OK for JobId=%d\n", elabel.JobId);
break;
case EOM_LABEL:
print_ls_output(fname, lname, type, &statp);
}
create_file_attributes_record(db, fname, lname, type, ap, rec);
- if (FirstIndex == 0) {
- FirstIndex = rec->FileIndex;
- }
- LastIndex = rec->FileIndex;
/* Data stream and extracting */
} else if (rec->Stream == STREAM_FILE_DATA) {
- } else if (rec->Stream != STREAM_MD5_SIGNATURE) {
- Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data);
+ } else if (rec->Stream == STREAM_GZIP_DATA) {
+
+ } else if (rec->Stream == STREAM_MD5_SIGNATURE) {
+ if (verbose > 1) {
+ Pmsg0(000, _("Got MD5 record.\n"));
+ }
+ /* ****FIXME**** implement db_update_md5_record */
+ } else {
+ Pmsg2(0, _("Unknown stream type!!! stream=%d data=%s\n"), rec->Stream, rec->data);
}
-
return;
}
-static void create_file_attributes_record(B_DB *db, char *fname, char *lname, int type,
+/*
+ * Free the Job Control Record if no one is still using it.
+ * Called from main free_jcr() routine in src/lib/jcr.c so
+ * that we can do our Director specific cleanup of the jcr.
+ */
+static void dird_free_jcr(JCR *jcr)
+{
+ Dmsg0(200, "Start dird free_jcr\n");
+
+ if (jcr->file_bsock) {
+ Dmsg0(200, "Close File bsock\n");
+ bnet_close(jcr->file_bsock);
+ }
+ if (jcr->store_bsock) {
+ Dmsg0(200, "Close Store bsock\n");
+ bnet_close(jcr->store_bsock);
+ }
+ if (jcr->RestoreBootstrap) {
+ free(jcr->RestoreBootstrap);
+ }
+ Dmsg0(200, "End dird free_jcr\n");
+}
+
+/*
+ * We got a File Attributes record on the tape. Now, lookup the Job
+ * record, and then create the attributes record.
+ */
+static int create_file_attributes_record(B_DB *db, char *fname, char *lname, int type,
char *ap, DEV_RECORD *rec)
{
+ JCR *mjcr;
+
if (!update_db) {
- return;
+ return 1;
+ }
+
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ Pmsg2(000, _("Could not find Job SessId=%d SessTime=%d for Attributes record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ return 0;
}
ar.fname = fname;
ar.link = lname;
- ar.ClientId = cr.ClientId;
- ar.JobId = jr.JobId;
+ ar.ClientId = mjcr->ClientId;
+ ar.JobId = mjcr->JobId;
ar.Stream = rec->Stream;
ar.FileIndex = rec->FileIndex;
ar.attr = ap;
+ if (mjcr->VolFirstFile == 0) {
+ mjcr->VolFirstFile = rec->FileIndex;
+ }
+ mjcr->FileIndex = rec->FileIndex;
+ free_jcr(mjcr); /* done using JCR */
+
if (!db_create_file_attributes_record(db, &ar)) {
Pmsg1(0, _("Could not create File Attributes record. ERR=%s\n"), db_strerror(db));
+ return 0;
}
-
+ if (verbose > 1) {
+ Pmsg1(000, _("Created File record: %s\n"), fname);
+ }
+ return 1;
}
-static void create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
+/*
+ * For each Volume we see, we create a Medium record
+ */
+static int create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl)
{
struct date_time dt;
struct tm tm;
if (!update_db) {
- return;
+ return 1;
}
strcpy(mr->VolStatus, "Full");
mr->VolRetention = 355 * 3600 * 24; /* 1 year */
mr->LabelDate = mktime(&tm);
if (!db_create_media_record(db, mr)) {
Pmsg1(0, _("Could not create media record. ERR=%s\n"), db_strerror(db));
+ return 0;
}
if (!db_update_media_record(db, mr)) {
Pmsg1(0, _("Could not update media record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg2(000, _("Created Media record for Volume: %s, JobId: %d\n"),
+ mr->VolumeName, jr.JobId);
}
+ return 1;
}
-static void create_pool_record(B_DB *db, POOL_DBR *pr)
+static int create_pool_record(B_DB *db, POOL_DBR *pr)
{
if (!update_db) {
- return;
+ return 1;
}
pr->NumVols++;
pr->UseCatalog = 1;
pr->VolRetention = 355 * 3600 * 24; /* 1 year */
if (!db_create_pool_record(db, pr)) {
Pmsg1(0, _("Could not create pool record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created Pool record for Pool: %s\n"), pr->Name);
}
+ return 1;
}
-static void create_client_record(B_DB *db, CLIENT_DBR *cr)
+/*
+ * Called from SOS to create a client for the current Job
+ */
+static int create_client_record(B_DB *db, CLIENT_DBR *cr)
{
if (!update_db) {
- return;
+ return 1;
}
if (!db_create_client_record(db, cr)) {
Pmsg1(0, _("Could not create Client record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created Client record for Client: %s\n"), cr->Name);
}
+ return 1;
}
-static void create_fileset_record(B_DB *db, FILESET_DBR *fsr)
+static int create_fileset_record(B_DB *db, FILESET_DBR *fsr)
{
if (!update_db) {
- return;
+ return 1;
}
if (!db_create_fileset_record(db, fsr)) {
Pmsg1(0, _("Could not create FileSet record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created FileSet record %s\n"), fsr->FileSet);
}
+ return 1;
}
-static void create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label)
+/*
+ * Simulate the two calls on the database to create
+ * the Job record and to update it when the Job actually
+ * begins running.
+ */
+static int create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label,
+ DEV_RECORD *rec)
{
struct date_time dt;
struct tm tm;
if (!update_db) {
- return;
+ return 1;
}
+ Pmsg1(000, _("Creating Job record for JobId: %d\n"), jr->JobId);
+
jr->JobId = label->JobId;
jr->Type = label->JobType;
jr->Level = label->JobLevel;
+ jr->JobStatus = JS_Created;
strcpy(jr->Name, label->JobName);
strcpy(jr->Job, label->Job);
dt.julian_day_number = label->write_date;
jr->SchedTime = mktime(&tm);
jr->StartTime = jr->SchedTime;
jr->JobTDate = (btime_t)jr->SchedTime;
+ jr->VolSessionId = rec->VolSessionId;
+ jr->VolSessionTime = rec->VolSessionTime;
+
+ /* This creates the bare essentials */
if (!db_create_job_record(db, jr)) {
Pmsg1(0, _("Could not create job record. ERR=%s\n"), db_strerror(db));
+ return 0;
}
-
+ /* Now create a JCR as if starting the Job */
+ create_jcr(jr, rec, label->JobId);
+
+ /* This adds the client, StartTime, JobTDate, ... */
+ if (!db_update_job_start_record(db, jr)) {
+ Pmsg1(0, _("Could not update job start record. ERR=%s\n"), db_strerror(db));
+ return 0;
+ }
+ if (verbose) {
+ Pmsg1(000, _("Created Job record for JobId: %d\n"), jr->JobId);
+ }
+ return 1;
}
-static void update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel,
+/*
+ * Simulate the database call that updates the Job
+ * at Job termination time.
+ */
+static int update_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *elabel,
DEV_RECORD *rec)
{
struct date_time dt;
struct tm tm;
+ JCR *mjcr;
if (!update_db) {
- return;
+ return 1;
+ }
+ mjcr = get_jcr_by_session(rec->VolSessionId, rec->VolSessionTime);
+ if (!mjcr) {
+ Pmsg2(000, _("Could not find SessId=%d SessTime=%d for EOS record.\n"),
+ rec->VolSessionId, rec->VolSessionTime);
+ return 0;
}
dt.julian_day_number = elabel->write_date;
dt.julian_day_fraction = elabel->write_time;
tm_decode(&dt, &tm);
- jr->JobStatus = JS_Terminated;
+ jr->JobId = mjcr->JobId;
+ jr->JobStatus = JS_Terminated; /* ***FIXME*** need to add to EOS label */
jr->EndTime = mktime(&tm);
jr->JobFiles = elabel->JobFiles;
jr->JobBytes = elabel->JobBytes;
jr->VolSessionId = rec->VolSessionId;
jr->VolSessionTime = rec->VolSessionTime;
- if (!db_create_job_record(db, jr)) {
- Pmsg1(0, _("Could not create job record. ERR=%s\n"), db_strerror(db));
+ jr->JobTDate = (btime_t)mjcr->start_time;
+ jr->ClientId = mjcr->ClientId;
+ if (!db_update_job_end_record(db, jr)) {
+ Pmsg1(0, _("Could not update job record. ERR=%s\n"), db_strerror(db));
+ free_jcr(mjcr);
+ return 0;
}
-
+ if (verbose) {
+ Pmsg1(000, _("Updated Job termination record for JobId: %d\n"), jr->JobId);
+ }
+ free_jcr(mjcr);
+ return 1;
}
-static void create_jobmedia_record(B_DB *db, JOBMEDIA_DBR *jmr, SESSION_LABEL *elabel)
+static int create_jobmedia_record(B_DB *db, JCR *mjcr)
{
+ JOBMEDIA_DBR jmr;
+
if (!update_db) {
- return;
+ return 1;
}
- jmr->FirstIndex = FirstIndex;
- jmr->LastIndex = LastIndex;
- jmr->StartFile = elabel->start_file;
- jmr->EndFile = elabel->end_file;
- jmr->StartBlock = elabel->start_block;
- jmr->EndBlock = elabel->end_block;
- if (!db_create_jobmedia_record(db, jmr)) {
+ memset(&jmr, 0, sizeof(jmr));
+ jmr.JobId = mjcr->JobId;
+ jmr.MediaId = mr.MediaId;
+ jmr.FirstIndex = mjcr->VolFirstFile;
+ jmr.LastIndex = mjcr->FileIndex;
+ jmr.StartFile = mjcr->start_file;
+ jmr.EndFile = mjcr->end_file;
+ jmr.StartBlock = mjcr->start_block;
+ jmr.EndBlock = mjcr->end_block;
+
+ if (!db_create_jobmedia_record(db, &jmr)) {
Pmsg1(0, _("Could not create JobMedia record. ERR=%s\n"), db_strerror(db));
+ return 0;
}
-
+ if (verbose) {
+ Pmsg2(000, _("Created JobMedia record JobId %d, MediaId %d\n"),
+ jmr.JobId, jmr.MediaId);
+ }
+ return 1;
}
+/*
+ * Create a JCR as if we are really starting the job
+ */
+static void create_jcr(JOB_DBR *jr, DEV_RECORD *rec, uint32_t JobId)
+{
+ /*
+ * Transfer as much as possible to the Job JCR. Most important is
+ * the JobId and the ClientId.
+ */
+ jobjcr = new_jcr(sizeof(JCR), dird_free_jcr);
+ jobjcr->JobType = jr->Type;
+ jobjcr->JobLevel = jr->Level;
+ jobjcr->JobStatus = jr->JobStatus;
+ strcpy(jobjcr->Job, jr->Job);
+ jobjcr->JobId = JobId; /* this is JobId on tape */
+ jobjcr->sched_time = jr->SchedTime;
+ jobjcr->start_time = jr->StartTime;
+ jobjcr->VolSessionId = rec->VolSessionId;
+ jobjcr->VolSessionTime = rec->VolSessionTime;
+ jobjcr->ClientId = jr->ClientId;
+ attach_jcr_to_device(dev, jobjcr);
+}
/* Dummies to replace askdir.c */
int dir_get_volume_info(JCR *jcr, int writing) { return 1;}
int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev)
{
+ /*
+ * We are at the end of reading a tape. Now, we simulate handling
+ * the end of writing a tape by wiffling through the attached
+ * jcrs creating jobmedia records.
+ */
+ Dmsg1(100, "Walk attached jcrs. Volume=%s\n", dev->VolCatInfo.VolCatName);
+ for (JCR *mjcr=NULL; (mjcr=next_attached_jcr(dev, mjcr)); ) {
+ if (verbose) {
+ Pmsg1(000, "create JobMedia for Job %s\n", mjcr->Job);
+ }
+ mjcr->end_block = dev->block_num;
+ mjcr->end_file = dev->file;
+ if (!create_jobmedia_record(db, mjcr)) {
+ Pmsg2(000, _("Could not create JobMedia record for Volume=%s Job=%s\n"),
+ dev->VolCatInfo.VolCatName, mjcr->Job);
+ }
+ }
+
fprintf(stderr, "Mount Volume %s on device %s and press return when ready: ",
jcr->VolumeName, dev_name(dev));
getchar();
return;
}
+/*
+ * Setup a "daemon" JCR for the various standalone
+ * tools (e.g. bls, bextract, bscan, ...)
+ */
JCR *setup_jcr(char *name, char *device, BSR *bsr)
{
JCR *jcr = new_jcr(sizeof(JCR), my_free_jcr);
}
Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
block->BlockNumber, rec->remainder);
+ /*
+ * We just have a new tape up, now read the label (first record)
+ * and pass it off to the callback routine, then continue
+ * most likely reading the previous record.
+ */
record = new_record();
read_block_from_device(dev, block);
read_record_from_block(block, record);
}
return buf;
}
-
/* Forward referenced functions */
void terminate_stored(int sig);
static void check_config();
-static void *director_thread(void *arg);
#define CONFIG_FILE "bacula-sd.conf" /* Default config file */
static int foreground = 0;
static workq_t dird_workq; /* queue for processing connections */
-static workq_t filed_workq; /* queue for processing connections */
static void usage()
int no_signals = FALSE;
int test_config = FALSE;
DEVRES *device;
- pthread_t dirid;
- int status;
init_stack_dump();
my_name_is(argc, argv, "stored");
start_watchdog(); /* start watchdog thread */
- /*
- * Here we support either listening on one port or on two ports
- */
- if (me->SDDport == 0 || me->SDDport == me->SDport) {
- /* Single server used for Director and File daemon */
- bnet_thread_server(me->SDport, me->max_concurrent_jobs * 2,
- &dird_workq, connection_request);
- } else {
- /* Start the Director server */
- if ((status=pthread_create(&dirid, NULL, director_thread,
- (void *)me->SDport)) != 0) {
- Emsg1(M_ABORT, 0, _("Cannot create Director thread: %s\n"), strerror(status));
- }
- /* Start File daemon server */
- bnet_thread_server(me->SDDport, 10, &filed_workq, connection_from_filed);
- /* never returns */
- }
-
+ /* Single server used for Director and File daemon */
+ bnet_thread_server(me->SDaddr, me->SDport, me->max_concurrent_jobs * 2 + 1,
+ &dird_workq, connection_request);
exit(1); /* to keep compiler quiet */
}
-static void *director_thread(void *arg)
-{
- int dir_port = (int)arg;
- pthread_detach(pthread_self());
- bnet_thread_server(dir_port, 10, &dird_workq, connection_request);
- return NULL;
-}
-
/* Return a new Session Id */
uint32_t newVolSessionId()
{
static struct res_items store_items[] = {
{"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
{"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
- {"address", store_str, ITEM(res_store.address), 0, 0, 0},
+ {"address", store_str, ITEM(res_store.address), 0, 0, 0}, /* deprecated */
+ {"sdaddress", store_str, ITEM(res_store.SDaddr), 0, 0, 0},
{"messages", store_res, ITEM(res_store.messages), 0, R_MSGS, 0},
{"sdport", store_int, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
- {"sddport", store_int, ITEM(res_store.SDDport), 0, 0, 0}, /* depricated */
+ {"sddport", store_int, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
{"workingdirectory", store_dir, ITEM(res_store.working_directory), 0, ITEM_REQUIRED, 0},
{"piddirectory", store_dir, ITEM(res_store.pid_directory), 0, ITEM_REQUIRED, 0},
{"subsysdirectory", store_dir, ITEM(res_store.subsys_directory), 0, ITEM_REQUIRED, 0},
sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
break;
case R_STORAGE:
- sendit(sock, "Storage: name=%s address=%s SDport=%d SDDport=%d\n",
- res->res_store.hdr.name, res->res_store.address,
+ sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d\n",
+ res->res_store.hdr.name, res->res_store.SDaddr,
res->res_store.SDport, res->res_store.SDDport);
break;
case R_DEVICE:
switch (type) {
case R_DIRECTOR:
- if (res->res_dir.password)
+ if (res->res_dir.password) {
free(res->res_dir.password);
- if (res->res_dir.address)
+ }
+ if (res->res_dir.address) {
free(res->res_dir.address);
+ }
break;
case R_STORAGE:
- if (res->res_store.address)
+ if (res->res_store.address) { /* ***FIXME*** deprecated */
free(res->res_store.address);
- if (res->res_store.working_directory)
+ }
+ if (res->res_store.SDaddr) {
+ free(res->res_store.SDaddr);
+ }
+ if (res->res_store.working_directory) {
free(res->res_store.working_directory);
- if (res->res_store.pid_directory)
+ }
+ if (res->res_store.pid_directory) {
free(res->res_store.pid_directory);
- if (res->res_store.subsys_directory)
+ }
+ if (res->res_store.subsys_directory) {
free(res->res_store.subsys_directory);
+ }
break;
case R_DEVICE:
- if (res->res_dev.media_type)
+ if (res->res_dev.media_type) {
free(res->res_dev.media_type);
- if (res->res_dev.device_name)
+ }
+ if (res->res_dev.device_name) {
free(res->res_dev.device_name);
- if (res->res_dev.changer_name)
+ }
+ if (res->res_dev.changer_name) {
free(res->res_dev.changer_name);
- if (res->res_dev.changer_command)
+ }
+ if (res->res_dev.changer_command) {
free(res->res_dev.changer_command);
+ }
break;
case R_MSGS:
- if (res->res_msgs.mail_cmd)
+ if (res->res_msgs.mail_cmd) {
free(res->res_msgs.mail_cmd);
- if (res->res_msgs.operator_cmd)
+ }
+ if (res->res_msgs.operator_cmd) {
free(res->res_msgs.operator_cmd);
+ }
free_msgs_res((MSGS *)res); /* free message resource */
res = NULL;
break;
*/
-#define R_FIRST 3001
+#define R_FIRST 3001
-#define R_DIRECTOR 3001
-#define R_STORAGE 3002
-#define R_DEVICE 3003
-#define R_MSGS 3004
+#define R_DIRECTOR 3001
+#define R_STORAGE 3002
+#define R_DEVICE 3003
+#define R_MSGS 3004
-#define R_LAST R_MSGS
+#define R_LAST R_MSGS
-#define R_NAME 3020
-#define R_ADDRESS 3021
-#define R_PASSWORD 3022
-#define R_TYPE 3023
-#define R_BACKUP 3024
+#define R_NAME 3020
+#define R_ADDRESS 3021
+#define R_PASSWORD 3022
+#define R_TYPE 3023
+#define R_BACKUP 3024
#define STORAGE_DAEMON 1
/* Definition of the contents of each Resource */
struct s_res_dir {
- RES hdr;
+ RES hdr;
- char *password; /* Director password */
- char *address; /* Director IP address or zero */
+ char *password; /* Director password */
+ char *address; /* Director IP address or zero */
};
typedef struct s_res_dir DIRRES;
/* Storage daemon "global" definitions */
struct s_res_store {
- RES hdr;
+ RES hdr;
- char *address;
- int SDport; /* Where we listen for Directors */
+ char *address; /* deprecated */
+ char *SDaddr; /* bind address */
+ int SDport; /* Where we listen for Directors */
int SDDport; /* "Data" port where we listen for File daemons */
- char *working_directory; /* working directory for checkpoints */
+ char *working_directory; /* working directory for checkpoints */
char *pid_directory;
char *subsys_directory;
uint32_t max_concurrent_jobs; /* maximum concurrent jobs to run */
/* Device specific definitions */
struct s_res_dev {
- RES hdr;
-
- char *media_type; /* User assigned media type */
- char *device_name; /* Archive device name */
- char *changer_name; /* Changer device name */
- char *changer_command; /* Changer command -- external program */
- int cap_bits; /* Capabilities of this device */
- uint32_t max_changer_wait; /* Changer timeout */
- uint32_t max_rewind_wait; /* maximum secs to wait for rewind */
- uint32_t max_open_wait; /* maximum secs to wait for open */
- uint32_t min_block_size; /* min block size */
- uint32_t max_block_size; /* max block size */
- uint32_t max_volume_jobs; /* max jobs to put on one volume */
- int64_t max_volume_files; /* max files to put on one volume */
- int64_t max_volume_size; /* max bytes to put on one volume */
- int64_t max_file_size; /* max file size in bytes */
- int64_t volume_capacity; /* advisory capacity */
- DEVICE *dev; /* Pointer to phyical dev -- set at runtime */
+ RES hdr;
+
+ char *media_type; /* User assigned media type */
+ char *device_name; /* Archive device name */
+ char *changer_name; /* Changer device name */
+ char *changer_command; /* Changer command -- external program */
+ int cap_bits; /* Capabilities of this device */
+ uint32_t max_changer_wait; /* Changer timeout */
+ uint32_t max_rewind_wait; /* maximum secs to wait for rewind */
+ uint32_t max_open_wait; /* maximum secs to wait for open */
+ uint32_t min_block_size; /* min block size */
+ uint32_t max_block_size; /* max block size */
+ uint32_t max_volume_jobs; /* max jobs to put on one volume */
+ int64_t max_volume_files; /* max files to put on one volume */
+ int64_t max_volume_size; /* max bytes to put on one volume */
+ int64_t max_file_size; /* max file size in bytes */
+ int64_t volume_capacity; /* advisory capacity */
+ DEVICE *dev; /* Pointer to phyical dev -- set at runtime */
};
typedef struct s_res_dev DEVRES;
union u_res {
- struct s_res_dir res_dir;
- struct s_res_store res_store;
- struct s_res_dev res_dev;
- struct s_res_msgs res_msgs;
+ struct s_res_dir res_dir;
+ struct s_res_store res_store;
+ struct s_res_dev res_dev;
+ struct s_res_msgs res_msgs;
RES hdr;
};
typedef union u_res URES;
/* */
#define VERSION "1.26"
#define VSTRING "1"
-#define DATE "21 September 2002"
-#define LSMDATE "21Sep02"
+#define DATE "25 September 2002"
+#define LSMDATE "25Sep02"
/* Debug flags */
#define DEBUG 1