From 6addd2c0541a270fc5ea2fa1b7c9900aea4cde8a Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Wed, 25 Sep 2002 21:12:36 +0000 Subject: [PATCH] Server address binding + bscan updates -- see kes25Sep02 git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@163 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/ChangeLog | 23 +- bacula/src/cats/Makefile.in | 3 +- bacula/src/dird/dird.c | 4 +- bacula/src/dird/dird_conf.c | 25 +- bacula/src/dird/dird_conf.h | 1 + bacula/src/dird/job.c | 1 - bacula/src/dird/ua_input.c | 2 +- bacula/src/dird/ua_server.c | 16 +- bacula/src/filed/filed.c | 3 +- bacula/src/filed/filed_conf.c | 19 +- bacula/src/filed/filed_conf.h | 35 +-- bacula/src/findlib/Makefile.in | 5 +- bacula/src/jcr.h | 8 +- bacula/src/lib/Makefile.in | 3 +- bacula/src/lib/bnet_server.c | 15 +- bacula/src/lib/jcr.c | 21 ++ bacula/src/lib/protos.h | 194 +++++++------- bacula/src/lib/util.c | 1 + bacula/src/stored/bacula-sd.conf.in | 1 - bacula/src/stored/bscan.c | 383 +++++++++++++++++++++------- bacula/src/stored/butil.c | 4 + bacula/src/stored/read_record.c | 6 +- bacula/src/stored/stored.c | 33 +-- bacula/src/stored/stored_conf.c | 48 ++-- bacula/src/stored/stored_conf.h | 81 +++--- bacula/src/version.h | 4 +- 26 files changed, 604 insertions(+), 335 deletions(-) diff --git a/bacula/ChangeLog b/bacula/ChangeLog index dc2b70f75e..9dafa5c9e6 100644 --- a/bacula/ChangeLog +++ b/bacula/ChangeLog @@ -1,6 +1,27 @@ 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 diff --git a/bacula/src/cats/Makefile.in b/bacula/src/cats/Makefile.in index 9dcfd645f4..fbdf8801c5 100644 --- a/bacula/src/cats/Makefile.in +++ b/bacula/src/cats/Makefile.in @@ -44,7 +44,8 @@ all: Makefile libsql.a @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 diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index 26eed34c97..7401a340c6 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -43,7 +43,7 @@ extern void term_scheduler(); 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); @@ -194,7 +194,7 @@ int main (int argc, char *argv[]) 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 */ diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 2b9c2f781d..1fd62959b6 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -88,6 +88,7 @@ static struct res_items dir_items[] = { {"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}, @@ -642,22 +643,32 @@ void free_resource(int type) 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) diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 67a9fb8d15..11c47bdfc3 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -84,6 +84,7 @@ struct s_jt { 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 */ diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 1ed219546f..ebf9bac1b4 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -45,7 +45,6 @@ extern int do_backup(JCR *jcr); 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 */ diff --git a/bacula/src/dird/ua_input.c b/bacula/src/dird/ua_input.c index 8cd28d37b3..5ad9ae5369 100644 --- a/bacula/src/dird/ua_input.c +++ b/bacula/src/dird/ua_input.c @@ -48,7 +48,7 @@ int get_cmd(UAContext *ua, char *prompt) 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); diff --git a/bacula/src/dird/ua_server.c b/bacula/src/dird/ua_server.c index a2af20fc7a..4a1e9ff639 100644 --- a/bacula/src/dird/ua_server.c +++ b/bacula/src/dird/ua_server.c @@ -58,16 +58,24 @@ static void handle_UA_client_request(void *arg); 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; @@ -76,12 +84,12 @@ void start_UA_server(int UA_port) 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; } diff --git a/bacula/src/filed/filed.c b/bacula/src/filed/filed.c index 9496f00255..851e3b2b19 100644 --- a/bacula/src/filed/filed.c +++ b/bacula/src/filed/filed.c @@ -199,7 +199,8 @@ Without that I don't know who I am :-(\n"), configfile); /* 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 */ } diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c index 3bb886ff95..484116c1bf 100644 --- a/bacula/src/filed/filed_conf.c +++ b/bacula/src/filed/filed_conf.c @@ -74,6 +74,7 @@ static struct res_items cli_items[] = { {"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}, @@ -174,18 +175,26 @@ void free_resource(int type) 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) diff --git a/bacula/src/filed/filed_conf.h b/bacula/src/filed/filed_conf.h index 40c28ba361..956070999b 100644 --- a/bacula/src/filed/filed_conf.h +++ b/bacula/src/filed/filed_conf.h @@ -28,34 +28,35 @@ /* * 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; @@ -70,9 +71,9 @@ typedef struct s_res_client CLIENT; * 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; }; diff --git a/bacula/src/findlib/Makefile.in b/bacula/src/findlib/Makefile.in index 1a66eca54b..6b84dac1a4 100644 --- a/bacula/src/findlib/Makefile.in +++ b/bacula/src/findlib/Makefile.in @@ -36,8 +36,9 @@ all: Makefile libfind.a ../lib/libbac.a @echo " " libfind.a: $(LIBOBJS) - $(RMF) libfind.a - $(AR) crs $@ $(LIBOBJS) + $(RMF) $@ + $(AR) cr $@ $(LIBOBJS) + $(RANLIB) $@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status cd $(topdir) \ diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 26e24a99d0..dc4d775ba1 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -108,6 +108,7 @@ struct s_jcr { 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 */ @@ -128,8 +129,7 @@ struct s_jcr { 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 */ @@ -137,7 +137,7 @@ struct s_jcr { 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 */ @@ -191,6 +191,7 @@ struct s_jcr { 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 */ @@ -238,6 +239,7 @@ extern JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr); 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); diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index df0ba1335b..7c288c4e9d 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -88,7 +88,8 @@ all: Makefile libbac.a @echo " " libbac.a: $(LIBOBJS) - $(AR) rcs $@ $(LIBOBJS) + $(AR) rc $@ $(LIBOBJS) + $(RANLIB) $@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status diff --git a/bacula/src/lib/bnet_server.c b/bacula/src/lib/bnet_server.c index 0b9f6ebee2..1841e0f69d 100644 --- a/bacula/src/lib/bnet_server.c +++ b/bacula/src/lib/bnet_server.c @@ -39,13 +39,14 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* 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; @@ -75,9 +76,17 @@ bnet_thread_server(int port, int max_clients, workq_t *client_wq, /* * 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 */ diff --git a/bacula/src/lib/jcr.c b/bacula/src/lib/jcr.c index 6657dffeda..92b529fbda 100755 --- a/bacula/src/lib/jcr.c +++ b/bacula/src/lib/jcr.c @@ -213,6 +213,27 @@ JCR *get_jcr_by_id(uint32_t JobId) 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; +} /* diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 5ee1231389..390b207829 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -24,143 +24,143 @@ */ /* 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); diff --git a/bacula/src/lib/util.c b/bacula/src/lib/util.c index c8f65699ab..92ba70d363 100644 --- a/bacula/src/lib/util.c +++ b/bacula/src/lib/util.c @@ -432,6 +432,7 @@ char *job_type_to_str(int type) break; case JT_ADMIN: str = _("Admin"); + break; default: str = _("Unknown Type"); break; diff --git a/bacula/src/stored/bacula-sd.conf.in b/bacula/src/stored/bacula-sd.conf.in index f3952d50d1..0e936dd705 100644 --- a/bacula/src/stored/bacula-sd.conf.in +++ b/bacula/src/stored/bacula-sd.conf.in @@ -12,7 +12,6 @@ Storage { # definition of myself Name = @hostname@-sd - Address = @hostname@ SDPort = @sd_port@ # Director's port WorkingDirectory = "@working_dir@" Pid Directory = "@piddir@" diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 2a7aaf3814..de17a011c0 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -37,22 +37,24 @@ /* 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; @@ -64,13 +66,10 @@ static MEDIA_DBR mr; 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"; @@ -81,7 +80,7 @@ static int update_db = 0; static void usage() { - fprintf(stderr, + fprintf(stderr, _( "\nVersion: " VERSION " (" DATE ")\n\n" "Usage: bscan [-d debug_level] \n" " -b bootstrap specify a bootstrap file\n" @@ -92,7 +91,7 @@ static void usage() " -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); } @@ -104,7 +103,7 @@ int main (int argc, char *argv[]) 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); @@ -149,7 +148,7 @@ int main (int argc, char *argv[]) argv += optind; if (argc != 1) { - Pmsg0(0, "Wrong number of arguments: \n"); + Pmsg0(0, _("Wrong number of arguments: \n")); usage(); } @@ -158,13 +157,15 @@ int main (int argc, char *argv[]) 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]); @@ -186,13 +187,13 @@ static void do_scan(char *devname) 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); @@ -223,13 +224,14 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) /* 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", @@ -240,16 +242,18 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } /* 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", @@ -258,21 +262,42 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) } 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", @@ -296,40 +321,28 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) 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: @@ -392,46 +405,97 @@ static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec) 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 */ @@ -445,59 +509,93 @@ static void create_media_record(B_DB *db, MEDIA_DBR *mr, VOLUME_LABEL *vl) 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; @@ -506,54 +604,123 @@ static void create_job_record(B_DB *db, JOB_DBR *jr, SESSION_LABEL *label) 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;} @@ -567,6 +734,24 @@ int dir_send_job_status(JCR *jcr) {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(); diff --git a/bacula/src/stored/butil.c b/bacula/src/stored/butil.c index 668dbec46f..323e714ec8 100644 --- a/bacula/src/stored/butil.c +++ b/bacula/src/stored/butil.c @@ -113,6 +113,10 @@ static void my_free_jcr(JCR *jcr) 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); diff --git a/bacula/src/stored/read_record.c b/bacula/src/stored/read_record.c index e78a2ee3c5..4720fce987 100644 --- a/bacula/src/stored/read_record.c +++ b/bacula/src/stored/read_record.c @@ -67,6 +67,11 @@ int read_records(JCR *jcr, DEVICE *dev, } 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); @@ -218,4 +223,3 @@ static char *rec_state_to_str(DEV_RECORD *rec) } return buf; } - diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index 498968b481..43d2145034 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -38,7 +38,6 @@ /* 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 */ @@ -61,7 +60,6 @@ static char *configfile; 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() @@ -90,8 +88,6 @@ int main (int argc, char *argv[]) int no_signals = FALSE; int test_config = FALSE; DEVRES *device; - pthread_t dirid; - int status; init_stack_dump(); my_name_is(argc, argv, "stored"); @@ -255,35 +251,12 @@ int main (int argc, char *argv[]) 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() { diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 8eed0fa907..2ff9448bee 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -54,10 +54,11 @@ int res_all_size = sizeof(res_all); 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}, @@ -145,8 +146,8 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... 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: @@ -245,36 +246,51 @@ void free_resource(int type) 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; diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 585030e9da..2c333b7656 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -23,42 +23,43 @@ */ -#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 */ @@ -68,32 +69,32 @@ typedef struct s_res_store STORES; /* 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; diff --git a/bacula/src/version.h b/bacula/src/version.h index 6c7343678c..e566b7bb3c 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #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 -- 2.39.2