From 1b347aae0cef9512378de98970930f18c3032cb7 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 21 Feb 2004 11:50:34 +0000 Subject: [PATCH] Start SIGHUP coding + misc git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1063 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/ChangeLog | 13 ++ bacula/autoconf/configure.in | 1 + bacula/kernstodo | 6 + bacula/platforms/suse/bacula-dir.in | 2 + bacula/platforms/suse/bacula-fd.in | 2 + bacula/platforms/suse/bacula-sd.in | 2 + bacula/platforms/suse/bacula.in | 213 +++++++++++++++++++++++ bacula/projects | 139 +++++++++++++++ bacula/src/baconfig.h | 3 + bacula/src/cats/sql_list.c | 8 +- bacula/src/console/console_conf.c | 1 - bacula/src/dird/dird.c | 29 ++- bacula/src/dird/dird_conf.c | 2 - bacula/src/dird/ua_output.c | 10 +- bacula/src/filed/filed_conf.c | 165 +++++++++--------- bacula/src/findlib/makepath.c | 2 +- bacula/src/gnome2-console/console_conf.c | 1 - bacula/src/lib/parse_conf.c | 42 ++++- bacula/src/lib/parse_conf.h | 4 +- bacula/src/lib/rwlock.c | 7 +- bacula/src/stored/bacula-sd.conf.in | 4 +- bacula/src/stored/stored_conf.c | 205 +++++++++++----------- bacula/src/win32/compat/winconfig.h | 7 +- bacula/src/win32/compat/winhost.h | 2 +- 24 files changed, 649 insertions(+), 221 deletions(-) create mode 100644 bacula/platforms/suse/bacula.in create mode 100644 bacula/projects diff --git a/bacula/ChangeLog b/bacula/ChangeLog index 639ac1bce5..269225cf7c 100644 --- a/bacula/ChangeLog +++ b/bacula/ChangeLog @@ -1,4 +1,17 @@ +21Feb04 +- Add Volker's bacula script to the SuSE directory and convert it + to bacula.in +- Make LockRes() and UnlockRes() use read/write locks and have + debug info to trace locking and unlocking. +- Begin work of implementing SIGHUP. It is now enabled for + the Director and works only if there are no jobs running, + in addition, if the new conf file is incorrect, it will + terminate Bacula. Much more work to be done. I've figured + out a scheme to implement it with running jobs without + adding individual semaphores or use counts. +- Sort "list jobs" by StartTime rather than JobId, which can + be random. 16Feb04 - Add a lot of "const" to char * arguments to keep the native Sun compiler happy. diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index a2362513cc..667dac318d 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -1467,6 +1467,7 @@ suse) platforms/suse/bacula-fd \ platforms/suse/bacula-sd \ platforms/suse/bacula-dir \ + platforms/suse/bacula \ platforms/suse/bacula.spec" ;; suse5) diff --git a/bacula/kernstodo b/bacula/kernstodo index 0898d3eba9..8a4831ec00 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -71,6 +71,12 @@ For 1.33 Testing/Documentation: http://howtos.linux.com/guides/nag2/x-087-2-nfs.mountd.shtml For 1.33 +- Remove h_errno from bnet.c by including proper header. +- Do not err job if could not write bootstrap file. +- Bizarre message: Error: Could not open WriteBootstrap file: +- Build console in client only build. +- For "list jobs" order by EndTime. +- Add "limit=n" for "list jobs" - Check new HAVE_WIN32 open bits. - Make column listing for running jobs. JobId Level Type Started Name Status diff --git a/bacula/platforms/suse/bacula-dir.in b/bacula/platforms/suse/bacula-dir.in index d7a2ea7956..d192063b68 100755 --- a/bacula/platforms/suse/bacula-dir.in +++ b/bacula/platforms/suse/bacula-dir.in @@ -1,5 +1,7 @@ #! /bin/sh # +# This file is reported not to work by Alan Brown 21Feb04 +# # bacula This shell script takes care of starting and stopping # the bacula Director daemon # diff --git a/bacula/platforms/suse/bacula-fd.in b/bacula/platforms/suse/bacula-fd.in index 72b0cecca6..ba270866c2 100755 --- a/bacula/platforms/suse/bacula-fd.in +++ b/bacula/platforms/suse/bacula-fd.in @@ -3,6 +3,8 @@ # bacula This shell script takes care of starting and stopping # the bacula File daemon. # +# This file is reported not to work by Alan Brown 21Feb04 +# # chkconfig: 2345 90 99 # description: It comes by night and sucks the vital essence from your computers. # diff --git a/bacula/platforms/suse/bacula-sd.in b/bacula/platforms/suse/bacula-sd.in index d79d9e7a5e..1c7013f27d 100755 --- a/bacula/platforms/suse/bacula-sd.in +++ b/bacula/platforms/suse/bacula-sd.in @@ -1,5 +1,7 @@ #! /bin/sh # +# This file is reported not to work by Alan Brown 21Feb04 +# # bacula This shell script takes care of starting and stopping # the bacula Storage daemon. # diff --git a/bacula/platforms/suse/bacula.in b/bacula/platforms/suse/bacula.in new file mode 100644 index 0000000000..832ec050f3 --- /dev/null +++ b/bacula/platforms/suse/bacula.in @@ -0,0 +1,213 @@ +#! /bin/sh +# +# bacula This shell script takes care of starting and stopping +# the bacula daemons. +# +# This is pretty much watered down version of the RedHat script +# that works on Solaris as well as Linux, but it won't work everywhere. +# +# Submitted by Volker Sauer 21Feb04 +# Tweaked a bit by Kern to convert it to a .in file +# +# description: It comes by night and sucks the vital essence from your computers. +# +### BEGIN INIT INFO +# Provides: bacula +# Required-Start: network mysql +# Required-Stop: +# Default-Start: 2 3 5 +# Default-Stop: +# Description: run bacula daemon(s) +### END INIT INFO + +PSCMD="@PSCMD@" +PIDDIR=@piddir@ +SUBSYSDIR=@subsysdir@ + +# A function to stop a program. +killproc() { + RC=0 + # Test syntax. + if [ $# = 0 ]; then + echo "Usage: killproc {program} [signal]" + return 1 + fi + + notset=0 + # check for third arg to be kill level + if [ "$3" != "" ] ; then + killlevel=$3 + else + notset=1 + killlevel="-9" + fi + + # Get base program name + base=`basename $1` + + # Find pid. + pid=`pidofproc $base $2` + + # Kill it. + if [ "$pid" != "" ] ; then + if [ "$notset" = "1" ] ; then + if ps -p $pid>/dev/null 2>&1; then + # TERM first, then KILL if not dead + kill -TERM $pid 2>/dev/null + sleep 1 + if ps -p $pid >/dev/null 2>&1 ; then + sleep 1 + if ps -p $pid >/dev/null 2>&1 ; then + sleep 3 + if ps -p $pid >/dev/null 2>&1 ; then + kill -KILL $pid 2>/dev/null + fi + fi + fi + fi + ps -p $pid >/dev/null 2>&1 + RC=$? + [ $RC -eq 0 ] && failure "$base shutdown" || success "$base shutdown" + # RC=$((! $RC)) + # use specified level only + else + if ps -p $pid >/dev/null 2>&1; then + kill $killlevel $pid 2>/dev/null + RC=$? + [ $RC -eq 0 ] && success "$base $killlevel" || failure "$base $killlevel" + fi + fi + else + failure "$base shutdown" + fi + # Remove pid file if any. + if [ "$notset" = "1" ]; then + rm -f ${PIDDIR}/$base.$2.pid + fi + return $RC +} + +# A function to find the pid of a program. +pidofproc() { + pid="" + # Test syntax. + if [ $# = 0 ] ; then + echo "Usage: pidofproc {program}" + return 1 + fi + + # Get base program name + base=`basename $1` + + # First try PID file + if [ -f ${PIDDIR}/$base.$2.pid ] ; then + pid=`head -1 ${PIDDIR}/$base.$2.pid` + if [ "$pid" != "" ] ; then + echo $pid + return 0 + fi + fi + + # Next try "pidof" + if [ -x /sbin/pidof ] ; then + pid=`/sbin/pidof $1` + fi + if [ "$pid" != "" ] ; then + echo $pid + return 0 + fi + + # Finally try to extract it from ps + ${PSCMD} | grep $1 | awk '{ print $1 }' | tr '\n' ' ' + return 0 +} + +status() { + # Test syntax. + if [ $# = 0 ] ; then + echo "Usage: status {program}" + return 1 + fi + + # Get base program name + base=`basename $1` + + # First try "pidof" + if [ -x /sbin/pidof ] ; then + pid=`/sbin/pidof $1` + fi + if [ "$pid" != "" ] ; then + echo "$base (pid $pid) is running..." + return 0 + else + pid=`${PSCMD} | awk 'BEGIN { prog=ARGV[1]; ARGC=1 } + { if ((prog == $2) || (("(" prog ")") == $2) || + (("[" prog "]") == $2) || + ((prog ":") == $2)) { print $1 ; exit 0 } }' $1` + if [ "$pid" != "" ] ; then + echo "$base (pid $pid) is running..." + return 0 + fi + fi + + # Next try the PID files + if [ -f ${PIDDIR}/$base.$2.pid ] ; then + pid=`head -1 ${PIDDIR}/$base.$2.pid` + if [ "$pid" != "" ] ; then + echo "$base dead but pid file exists" + return 1 + fi + fi + # See if the subsys lock exists + if [ -f ${SUBSYSDIR}/$base ] ; then + echo "$base dead but subsys locked" + return 2 + fi + echo "$base is stopped" + return 3 +} + +success() { + return 0 +} + +failure() { + rc=$? + return $rc +} + +case "$1" in + start) + echo "Starting the Storage daemon" + @sbindir@/bacula-sd $2 -v -c @sysconfdir@//bacula-sd.conf + echo "Starting the File daemon" + @sbindir@/bacula-fd $2 -v -c @sysconfdir@//bacula-fd.conf + sleep 2 + echo "Starting the Director daemon" + @sbindir@/bacula-dir $2 -v -c @sysconfdir@//bacula-dir.conf + ;; + stop) + echo "Stopping the File daemon" + killproc @sbindir@/bacula-fd 9102 + echo "Stopping the Storage daemon" + killproc @sbindir@/bacula-sd 9103 + echo "Stopping the Director daemon" + killproc @sbindir@/bacula-dir 9101 + echo + ;; + restart) + $0 stop + sleep 5 + $0 start + ;; + status) + status @sbindir@/bacula-sd 9103 + status @sbindir@/bacula-fd 9102 + status @sbindir@/bacula-dir 9101 + ;; + *) + echo "Usage: $0 {start|stop|restart|status}" + exit 1 + ;; +esac +exit 0 diff --git a/bacula/projects b/bacula/projects new file mode 100644 index 0000000000..8489863a0f --- /dev/null +++ b/bacula/projects @@ -0,0 +1,139 @@ + +Projects: + Bacula Projects Roadmap + 18 February 2004 + +Completed items from last year's list: +Item 1: Multiple simultaneous Jobs. (done) +Item 3: Write the bscan program -- also write a bcopy program (done). +Item 5: Implement Label templates (done). +Item 6: Write a regression script (done) +Item 9: Add SSL to daemon communications (For now, implement with stunnel) +Item 10: Define definitive tape format (done) + +Item 1: Implement Base jobs. + + What: A base job is sort of like a Full save except that you + will want the FileSet to contain only files that are unlikely + to change in the future (i.e. a snapshot of most of your + system after installing it). After the base job has been run, + when you are doing a Full save, you can specify to exclude + all files saved by the base job that have not been modified. + + Why: This is something none of the competition does, as far as we know + (except BackupPC, which is a Perl program that saves to disk + only). It is big win for the user, it makes Bacula stand out + as offering a unique optimization that immediately saves time + and money. + + Notes: Big savings in tape usage. Will require more resources because + the DIR must send FD a list of files/attribs, and the FD must + search the list and compare it for each file to be saved. + +Item 2: Make the Storage daemon use intermediate file storage to buffer data + or Data Spooling. + + What: If data is coming into the SD too fast, buffer it to + disk if the user has configured this option, so that tape + shuttling or shoe-shine can be reduced. + + Why: This would be a nice project and is the most requested feature. + Even though you may finish a client job quicker by spilling to + disk, you still have to eventually get it onto tape. If + intermediate disk buffering allows us to improve write + bandwidth to tape, it may make sense. In addition, you can + run multiple simultaneous jobs all spool to disk, then the + data can be written one job at a time to the tape at full + tape speed. This keeps the tape running smoothly and prevents + blocks from different simultaneous jobs from being intermixed + on the tape, which is very ineffficient for restores. + + Notes: + +Item 3: GUI for interactive restore +Item 4: GUI for interactive backup + + What: The current interactive restore is implemented with a tty + interface. It would be much nicer to be able to "see" the + list of files backed up in typical GUI tree format. + The same mechanism could also be used for creating + ad-hoc backup FileSets (item 8). + + Why: Ease of use -- especially for the end user. + + Notes: Rather than implementing in Gtk, we probably should go directly + for a Browser implementation, even if doing so meant the + capability wouldn't be available until much later. Not only + is there the question of Windows sites, most + Solaris/HP/IRIX, etc, shops can't currently run Gtk programs + without installing lots of stuff admins are very wary about. + Real sysadmins will always use the command line anyway, and + the user who's doing an interactive restore or backup of his + own files will in most cases be on a Windows machine running + Exploder. + +Item 5: Implement data encryption (as opposed to communications + encryption) + + What: Currently the data that is stored on the Volume is not + encrypted. For confidentiality, encryption of data at + the File daemon level is essential. Note, communications + encryption encrypts the data when leaving the File daemon, + then decrypts the data on entry to the Storage daemon. + Data encryption encrypts the data in the File daemon and + decrypts the data in the File daemon during a restore. + + Why: Large sites require this. + + Notes: The only algorithm that is needed is AES. + http://csrc.nist.gov/CryptoToolkit/aes/ + +Item 6: Implement a Migration job type that will move the job + data from one device to another. + + What: The ability to copy, move, or archive data that is on a + device to another device is very important. + + Why: An ISP might want to backup to disk, but after 30 days + migrate the data to tape backup and delete it from disk. + Bacula should be able to handle this automatically. It needs to + know what was put where, and when, and what to migrate -- it + is a bit like retention periods. Doing so would allow space to + be freed up for current backups while maintaining older data on + tape drives. + + Notes: Migration could be triggered by: + Number of Jobs + Number of Volumes + Age of Jobs + Highwater size (keep total size) + Lowwater mark + + +Item 7: New daemon communication protocol. + + What: The current daemon to daemon protocol is basically an ASCII + printf() and sending the buffer. On the receiving end, the + buffer is sscanf()ed to unpack it. The new scheme would + retain the current ASCII sending, but would add an + argc, argv like table driven scanner to replace sscanf. + + Why: Named fields will permit error checking to ensure that what is + sent is what the receiver really wants. The fields can be in + any order and additional fields can be ignored allowing better + upward compatibility. Much better checking of the types and + values passed can be done. + + Notes: These are internal improvements in the interest of the + long-term stability and evolution of the program. On the one + hand, the sooner they're done, the less code we have to rip + up when the time comes to install them. On the other hand, they + don't bring an immediately perceptible benefit to potential + users. + +To be documented: +Embedded Perl Scripting +Implement events +Multiple Storage devices for a single job +Write to more than one device simultaneously +Break the one-to-one relation between Storage and device diff --git a/bacula/src/baconfig.h b/bacula/src/baconfig.h index eebeea0dc4..35698e8c1d 100644 --- a/bacula/src/baconfig.h +++ b/bacula/src/baconfig.h @@ -260,6 +260,9 @@ extern void _v(char *file, int line, pthread_mutex_t *m); strerror(errstat)); \ } while(0) +#define LockRes() b_LockRes(__FILE__, __LINE__) +#define UnlockRes() b_UnlockRes(__FILE__, __LINE__) + /* * The digit following Dmsg and Emsg indicates the number of substitutions in diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index 4edbdddd57..428e4ae8fd 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -232,7 +232,7 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, "JobMissingFiles,Job.PoolId,Pool.Name,Job.FileSetId,FileSet.FileSet " "FROM Job,Client,Pool,FileSet WHERE " "Client.ClientId=Job.ClientId AND Pool.PoolId=Job.PoolId " - "AND FileSet.FileSetId=Job.FileSetId ORDER BY JobId"); + "AND FileSet.FileSetId=Job.FileSetId ORDER BY StartTime"); } else { /* single record */ Mmsg(&mdb->cmd, "SELECT JobId,Job,Job.Name,PurgedFiles,Type,Level," @@ -248,7 +248,7 @@ db_list_job_records(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, if (jr->JobId == 0 && jr->Job[0] == 0) { Mmsg(&mdb->cmd, "SELECT JobId,Name,StartTime,Type,Level,JobFiles,JobBytes,JobStatus " - "FROM Job ORDER BY JobId"); + "FROM Job ORDER BY StartTime"); } else { /* single record */ Mmsg(&mdb->cmd, "SELECT JobId,Name,StartTime,Type,Level," "JobFiles,JobBytes,JobStatus FROM Job WHERE JobId=%u", jr->JobId); @@ -274,8 +274,8 @@ db_list_job_totals(JCR *jcr, B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, vo db_lock(mdb); /* List by Job */ - Mmsg(&mdb->cmd, "SELECT count(*) AS Jobs, sum(JobFiles) \ -AS Files, sum(JobBytes) AS Bytes, Name AS Job FROM Job GROUP BY Name"); + Mmsg(&mdb->cmd, "SELECT count(*) AS Jobs,sum(JobFiles) " + "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name"); if (!QUERY_DB(jcr, mdb, mdb->cmd)) { db_unlock(mdb); diff --git a/bacula/src/console/console_conf.c b/bacula/src/console/console_conf.c index daeebc898b..9def219279 100644 --- a/bacula/src/console/console_conf.c +++ b/bacula/src/console/console_conf.c @@ -47,7 +47,6 @@ */ int r_first = R_FIRST; int r_last = R_LAST; -pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER; /* Forward referenced subroutines */ diff --git a/bacula/src/dird/dird.c b/bacula/src/dird/dird.c index 8842bc6267..6fb1cd4e28 100644 --- a/bacula/src/dird/dird.c +++ b/bacula/src/dird/dird.c @@ -211,7 +211,7 @@ int main (int argc, char *argv[]) drop(uid, gid); /* reduce priveleges if requested */ -/* signal(SIGHUP, reload_config); */ + signal(SIGHUP, reload_config); init_console_msg(working_directory); @@ -280,8 +280,10 @@ static void terminate_dird(int sig) */ static void reload_config(int sig) { - static int already_here = FALSE; + static bool already_here = false; sigset_t set; + JCR *jcr; + int njobs = 0; if (already_here) { abort(); /* Oops, recursion -> die */ @@ -290,11 +292,23 @@ static void reload_config(int sig) sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); + lock_jcr_chain(); + LockRes(); + + foreach_jcr(jcr) { + if (jcr->JobId != 0) { /* this is a console */ + njobs++; + } + free_locked_jcr(jcr); + } + if (njobs > 0) { + goto bail_out; + } + free_config_resources(); parse_config(configfile); - Dmsg0(200, "check_resources()\n"); if (!check_resources()) { Jmsg(NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile); } @@ -303,11 +317,14 @@ static void reload_config(int sig) set_working_directory(director->working_directory); FDConnectTimeout = director->FDConnectTimeout; SDConnectTimeout = director->SDConnectTimeout; - + Dmsg0(0, "Director's configuration file reread.\n"); + +bail_out: + UnlockRes(); + unlock_jcr_chain(); sigprocmask(SIG_UNBLOCK, &set, NULL); signal(SIGHUP, reload_config); - already_here = FALSE; - Dmsg0(0, "Director's configuration file reread.\n"); + already_here = false; } /* diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index ebea539c10..d567a3bbf3 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -51,8 +51,6 @@ int r_first = R_FIRST; int r_last = R_LAST; -pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER; - /* Imported subroutines */ extern void store_run(LEX *lc, struct res_items *item, int index, int pass); extern void store_finc(LEX *lc, struct res_items *item, int index, int pass); diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c index 55d81ebb9c..d8417e4370 100644 --- a/bacula/src/dird/ua_output.c +++ b/bacula/src/dird/ua_output.c @@ -108,6 +108,7 @@ int show_cmd(UAContext *ua, char *cmd) Dmsg1(20, "show: %s\n", ua->UA_sock->msg); + LockRes(); for (i=1; iargc; i++) { type = 0; res_name = ua->argk[i]; @@ -126,6 +127,7 @@ int show_cmd(UAContext *ua, char *cmd) break; } } + } else { /* Dump a single resource with specified name */ recurse = 0; @@ -153,18 +155,20 @@ int show_cmd(UAContext *ua, char *cmd) for (j=0; reses[j].res_name; j++) { bsendmsg(ua, "%s\n", _(reses[j].res_name)); } - return 1; + goto bail_out; case -3: bsendmsg(ua, _("%s resource %s not found.\n"), res_name, ua->argv[i]); - return 1; + goto bail_out; case 0: bsendmsg(ua, _("Resource %s not found\n"), res_name); - return 1; + goto bail_out; default: dump_resource(recurse?type:-type, res, bsendmsg, ua); break; } } +bail_out: + UnlockRes(); return 1; } diff --git a/bacula/src/filed/filed_conf.c b/bacula/src/filed/filed_conf.c index 8767ad3733..4c37767bb2 100644 --- a/bacula/src/filed/filed_conf.c +++ b/bacula/src/filed/filed_conf.c @@ -8,14 +8,14 @@ * 1. The generic lexical scanner in lib/lex.c and lib/lex.h * * 2. The generic config scanner in lib/parse_config.c and - * lib/parse_config.h. - * These files contain the parser code, some utility - * routines, and the common store routines (name, int, - * string). + * lib/parse_config.h. + * These files contain the parser code, some utility + * routines, and the common store routines (name, int, + * string). * * 3. The daemon specific file, which contains the Resource - * definitions as well as any specific store routines - * for the resource records. + * definitions as well as any specific store routines + * for the resource records. * * Kern Sibbald, September MM * @@ -51,7 +51,6 @@ */ int r_first = R_FIRST; int r_last = R_LAST; -pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER; /* Forward referenced subroutines */ @@ -116,7 +115,7 @@ struct s_res resources[] = { {"filedaemon", cli_items, R_CLIENT, NULL}, {"client", cli_items, R_CLIENT, NULL}, /* alias for filedaemon */ {"messages", msgs_items, R_MSGS, NULL}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; @@ -130,26 +129,26 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... sendit(sock, "No record for %d %s\n", type, res_to_str(type)); return; } - if (type < 0) { /* no recursion */ + if (type < 0) { /* no recursion */ type = - type; recurse = 0; } switch (type) { case R_DIRECTOR: sendit(sock, "Director: name=%s password=%s\n", reshdr->name, - res->res_dir.password); - break; + res->res_dir.password); + break; case R_CLIENT: sendit(sock, "Client: name=%s FDport=%d\n", reshdr->name, - res->res_client.FDport); - break; + res->res_client.FDport); + break; case R_MSGS: sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); - if (res->res_msgs.mail_cmd) + if (res->res_msgs.mail_cmd) sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); - if (res->res_msgs.operator_cmd) + if (res->res_msgs.operator_cmd) sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); - break; + break; default: sendit(sock, "Unknown resource type %d\n", type); } @@ -187,35 +186,35 @@ void free_resource(int type) switch (type) { case R_DIRECTOR: - if (res->res_dir.password) { - free(res->res_dir.password); - } - if (res->res_dir.address) { - free(res->res_dir.address); - } - break; + if (res->res_dir.password) { + free(res->res_dir.password); + } + if (res->res_dir.address) { + free(res->res_dir.address); + } + break; case R_CLIENT: - if (res->res_client.working_directory) { - free(res->res_client.working_directory); - } - if (res->res_client.pid_directory) { - free(res->res_client.pid_directory); - } - if (res->res_client.subsys_directory) { - free(res->res_client.subsys_directory); - } - if (res->res_client.FDaddr) { - free(res->res_client.FDaddr); - } - break; + if (res->res_client.working_directory) { + free(res->res_client.working_directory); + } + if (res->res_client.pid_directory) { + free(res->res_client.pid_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) - free(res->res_msgs.mail_cmd); - if (res->res_msgs.operator_cmd) - free(res->res_msgs.operator_cmd); - free_msgs_res((MSGS *)res); /* free message resource */ - res = NULL; - break; + if (res->res_msgs.mail_cmd) + free(res->res_msgs.mail_cmd); + if (res->res_msgs.operator_cmd) + free(res->res_msgs.operator_cmd); + free_msgs_res((MSGS *)res); /* free message resource */ + res = NULL; + break; default: printf("Unknown resource type %d\n", type); } @@ -245,10 +244,10 @@ void save_resource(int type, struct res_items *items, int pass) */ for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { - if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { + if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"), - items[i].name, resources[rindex]); - } + items[i].name, resources[rindex]); + } } } @@ -259,33 +258,33 @@ void save_resource(int type, struct res_items *items, int pass) */ if (pass == 2) { switch (type) { - /* Resources not containing a resource */ - case R_MSGS: - case R_DIRECTOR: - break; + /* Resources not containing a resource */ + case R_MSGS: + case R_DIRECTOR: + break; - /* Resources containing another resource */ - case R_CLIENT: - if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) { + /* Resources containing another resource */ + case R_CLIENT: + if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_dir.hdr.name)) == NULL) { Emsg1(M_ABORT, 0, "Cannot find Client resource %s\n", res_all.res_dir.hdr.name); - } - res->res_client.messages = res_all.res_client.messages; - break; - default: + } + res->res_client.messages = res_all.res_client.messages; + break; + default: Emsg1(M_ERROR, 0, _("Unknown resource type %d\n"), type); - error = 1; - break; + error = 1; + break; } /* Note, the resoure name was already saved during pass 1, * so here, we can just release it. */ if (res_all.res_dir.hdr.name) { - free(res_all.res_dir.hdr.name); - res_all.res_dir.hdr.name = NULL; + free(res_all.res_dir.hdr.name); + res_all.res_dir.hdr.name = NULL; } if (res_all.res_dir.hdr.desc) { - free(res_all.res_dir.hdr.desc); - res_all.res_dir.hdr.desc = NULL; + free(res_all.res_dir.hdr.desc); + res_all.res_dir.hdr.desc = NULL; } return; } @@ -293,39 +292,39 @@ void save_resource(int type, struct res_items *items, int pass) /* The following code is only executed on pass 1 */ switch (type) { case R_DIRECTOR: - size = sizeof(DIRRES); - break; + size = sizeof(DIRRES); + break; case R_CLIENT: - size = sizeof(CLIENT); - break; + size = sizeof(CLIENT); + break; case R_MSGS: - size = sizeof(MSGS); - break; + size = sizeof(MSGS); + break; default: printf(_("Unknown resource type %d\n"), type); - error = 1; - size = 1; - break; + error = 1; + size = 1; + break; } /* Common */ if (!error) { res = (URES *)malloc(size); memcpy(res, &res_all, size); if (!resources[rindex].res_head) { - resources[rindex].res_head = (RES *)res; /* store first entry */ + resources[rindex].res_head = (RES *)res; /* store first entry */ } else { - RES *next; - /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) { - if (strcmp(next->name, res->res_dir.hdr.name) == 0) { - Emsg2(M_ERROR_TERM, 0, + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), - resources[rindex].name, res->res_dir.hdr.name); - } - } - next->next = (RES *)res; + resources[rindex].name, res->res_dir.hdr.name); + } + } + next->next = (RES *)res; Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), - res->res_dir.hdr.name); + res->res_dir.hdr.name); } } } diff --git a/bacula/src/findlib/makepath.c b/bacula/src/findlib/makepath.c index bc1fb33989..2932b83e4a 100644 --- a/bacula/src/findlib/makepath.c +++ b/bacula/src/findlib/makepath.c @@ -225,7 +225,7 @@ make_path( /* If we've saved the cwd and DIRPATH is an absolute pathname, we must chdir to `/' in order to enable the chdir optimization. So if chdir ("/") fails, turn off the optimization. */ - if (cwd.do_chdir && isAbsolute(dirpath) && chdir ("/") < 0) { + if (cwd.do_chdir && isAbsolute(dirpath) && (chdir("/") < 0)) { cwd.do_chdir = 0; } diff --git a/bacula/src/gnome2-console/console_conf.c b/bacula/src/gnome2-console/console_conf.c index 5c798a04b0..6c89c3a73a 100644 --- a/bacula/src/gnome2-console/console_conf.c +++ b/bacula/src/gnome2-console/console_conf.c @@ -49,7 +49,6 @@ */ int r_first = R_FIRST; int r_last = R_LAST; -pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER; /* Forward referenced subroutines */ diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index b21560d628..642fac588a 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -64,7 +64,6 @@ extern int debug_level; */ extern int r_first; extern int r_last; -extern pthread_mutex_t res_mutex; extern struct s_res resources[]; #ifdef HAVE_WIN32 // work around visual studio name manling preventing external linkage since res_all @@ -77,7 +76,8 @@ extern int res_all_size; #endif -static bool res_locked = false; /* set when resource chains locked */ +static brwlock_t res_lock; /* resource lock */ +static int res_locked = 0; /* set when resource chains locked -- for debug */ /* Forward referenced subroutines */ static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd); @@ -157,6 +157,14 @@ void init_resource(int type, struct res_items *items) { int i; int rindex = type - r_first; + static bool first = true; + int errstat; + + if (first && (errstat=rwl_init(&res_lock)) != 0) { + Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"), + strerror(errstat)); + } + first = false; memset(&res_all, 0, res_all_size); res_all.hdr.rcode = type; @@ -587,17 +595,34 @@ void store_yesno(LEX *lc, struct res_items *item, int index, int pass) } +/* #define TRACE_RES */ -void LockRes() +void b_LockRes(const char *file, int line) { - P(res_mutex); - res_locked = true; + int errstat; +#ifdef TRACE_RES + Dmsg4(000, "LockRes %d,%d at %s:%d\n", res_locked, res_lock.w_active, + file, line); +#endif + if ((errstat=rwl_writelock(&res_lock)) != 0) { + Emsg3(M_ABORT, 0, "rwl_writelock failure at %s:%d: ERR=%s\n", + file, line, strerror(errstat)); + } + res_locked++; } -void UnlockRes() +void b_UnlockRes(const char *file, int line) { - res_locked = false; - V(res_mutex); + int errstat; + res_locked--; +#ifdef TRACE_RES + Dmsg4(000, "UnLockRes %d,%d at %s:%d\n", res_locked, res_lock.w_active, + file, line); +#endif + if ((errstat=rwl_writeunlock(&res_lock)) != 0) { + Emsg3(M_ABORT, 0, "rwl_writeunlock failure at %s:%d:. ERR=%s\n", + file, line, strerror(errstat)); + } } /* @@ -782,5 +807,6 @@ free_config_resources() int i; for (i=r_first; i<=r_last; i++) { free_resource(i); + resources[i-r_first].res_head = NULL; } } diff --git a/bacula/src/lib/parse_conf.h b/bacula/src/lib/parse_conf.h index fe4be0fc04..d216e49e2f 100644 --- a/bacula/src/lib/parse_conf.h +++ b/bacula/src/lib/parse_conf.h @@ -103,8 +103,8 @@ void free_config_resources(void); /* Resource routines */ RES *GetResWithName(int rcode, char *name); RES *GetNextRes(int rcode, RES *res); -void LockRes(void); -void UnlockRes(void); +void b_LockRes(const char *file, int line); +void b_UnlockRes(const char *file, int line); void dump_resource(int type, RES *res, void sendmsg(void *sock, char *fmt, ...), void *sock); void free_resource(int type); void init_resource(int type, struct res_items *item); diff --git a/bacula/src/lib/rwlock.c b/bacula/src/lib/rwlock.c index 6729a31ca1..f6912b519d 100644 --- a/bacula/src/lib/rwlock.c +++ b/bacula/src/lib/rwlock.c @@ -236,7 +236,7 @@ int rwl_writelock(brwlock_t *rwl) rwl->w_wait--; /* we are no longer waiting */ } if (stat == 0) { - rwl->w_active = 1; /* we are running */ + rwl->w_active++; /* we are running */ rwl->writer_id = pthread_self(); /* save writer thread's id */ } pthread_mutex_unlock(&rwl->mutex); @@ -285,8 +285,11 @@ int rwl_writeunlock(brwlock_t *rwl) if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) { return stat; } + if (rwl->w_active <= 0) { + Emsg0(M_ABORT, 0, "rwl_writeunlock called too many times.\n"); + } rwl->w_active--; - if (rwl->w_active < 0 || !pthread_equal(pthread_self(), rwl->writer_id)) { + if (!pthread_equal(pthread_self(), rwl->writer_id)) { Emsg0(M_ABORT, 0, "rwl_writeunlock by non-owner.\n"); } if (rwl->w_active > 0) { diff --git a/bacula/src/stored/bacula-sd.conf.in b/bacula/src/stored/bacula-sd.conf.in index 3cb2fcf513..c4e6bd8c2f 100644 --- a/bacula/src/stored/bacula-sd.conf.in +++ b/bacula/src/stored/bacula-sd.conf.in @@ -87,8 +87,8 @@ Device { # AlwaysOpen = yes # Offline On Unmount = no ## The min/max blocksizes of 32768 are *required* -# Minimum Block Size = 32768                              -#  Maximum Block Size = 32768 +# Minimum Block Size = 32768 +# Maximum Block Size = 32768 #} diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 206b0cb441..459a7d91d2 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -35,7 +35,6 @@ extern int debug_level; /* First and last resource ids */ int r_first = R_FIRST; int r_last = R_LAST; -pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER; /* Forward referenced subroutines */ @@ -131,7 +130,7 @@ struct s_res resources[] = { {"storage", store_items, R_STORAGE, NULL}, {"device", dev_items, R_DEVICE, NULL}, {"messages", msgs_items, R_MSGS, NULL}, - {NULL, NULL, 0, NULL} + {NULL, NULL, 0, NULL} }; @@ -147,7 +146,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... return; } sendit(sock, "dump_resource type=%d\n", type); - if (type < 0) { /* no recursion */ + if (type < 0) { /* no recursion */ type = - type; recurse = 0; } @@ -157,22 +156,22 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, char *fmt, ... break; case R_STORAGE: sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n", - res->res_store.hdr.name, NPRT(res->res_store.SDaddr), - res->res_store.SDport, res->res_store.SDDport, - edit_utime(res->res_store.heartbeat_interval, buf)); + res->res_store.hdr.name, NPRT(res->res_store.SDaddr), + res->res_store.SDport, res->res_store.SDDport, + edit_utime(res->res_store.heartbeat_interval, buf)); break; case R_DEVICE: sendit(sock, "Device: name=%s MediaType=%s Device=%s\n", - res->res_dev.hdr.name, - res->res_dev.media_type, res->res_dev.device_name); + res->res_dev.hdr.name, + res->res_dev.media_type, res->res_dev.device_name); sendit(sock, " rew_wait=%d min_bs=%d max_bs=%d\n", - res->res_dev.max_rewind_wait, res->res_dev.min_block_size, - res->res_dev.max_block_size); + res->res_dev.max_rewind_wait, res->res_dev.min_block_size, + res->res_dev.max_block_size); sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n", - res->res_dev.max_volume_jobs, res->res_dev.max_volume_files, - res->res_dev.max_volume_size); + res->res_dev.max_volume_jobs, res->res_dev.max_volume_files, + res->res_dev.max_volume_size); sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n", - res->res_dev.max_file_size, res->res_dev.volume_capacity); + res->res_dev.max_file_size, res->res_dev.volume_capacity); strcpy(buf, " "); if (res->res_dev.cap_bits & CAP_EOF) { bstrncat(buf, "CAP_EOF ", sizeof(buf)); @@ -257,57 +256,57 @@ void free_resource(int type) switch (type) { case R_DIRECTOR: - if (res->res_dir.password) { - free(res->res_dir.password); - } - if (res->res_dir.address) { - free(res->res_dir.address); - } - break; + if (res->res_dir.password) { + free(res->res_dir.password); + } + if (res->res_dir.address) { + free(res->res_dir.address); + } + break; case R_STORAGE: - if (res->res_store.address) { /* ***FIXME*** deprecated */ - free(res->res_store.address); - } - 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) { - free(res->res_store.pid_directory); - } - if (res->res_store.subsys_directory) { - free(res->res_store.subsys_directory); - } - break; + if (res->res_store.address) { /* ***FIXME*** deprecated */ + free(res->res_store.address); + } + 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) { + free(res->res_store.pid_directory); + } + if (res->res_store.subsys_directory) { + free(res->res_store.subsys_directory); + } + break; case R_DEVICE: - if (res->res_dev.media_type) { - free(res->res_dev.media_type); - } - if (res->res_dev.device_name) { - free(res->res_dev.device_name); - } - if (res->res_dev.changer_name) { - free(res->res_dev.changer_name); - } - if (res->res_dev.changer_command) { - free(res->res_dev.changer_command); - } - break; + if (res->res_dev.media_type) { + free(res->res_dev.media_type); + } + if (res->res_dev.device_name) { + free(res->res_dev.device_name); + } + if (res->res_dev.changer_name) { + free(res->res_dev.changer_name); + } + if (res->res_dev.changer_command) { + free(res->res_dev.changer_command); + } + break; case R_MSGS: - if (res->res_msgs.mail_cmd) { - free(res->res_msgs.mail_cmd); - } - if (res->res_msgs.operator_cmd) { - free(res->res_msgs.operator_cmd); - } - free_msgs_res((MSGS *)res); /* free message resource */ - res = NULL; - break; + if (res->res_msgs.mail_cmd) { + free(res->res_msgs.mail_cmd); + } + if (res->res_msgs.operator_cmd) { + free(res->res_msgs.operator_cmd); + } + free_msgs_res((MSGS *)res); /* free message resource */ + res = NULL; + break; default: Dmsg1(0, "Unknown resource type %d\n", type); - break; + break; } /* Common stuff again -- free the resource, recurse to next one */ if (res) { @@ -335,10 +334,10 @@ void save_resource(int type, struct res_items *items, int pass) */ for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { - if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { + if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { Emsg2(M_ABORT, 0, _("%s item is required in %s resource, but not found.\n"), - items[i].name, resources[rindex]); - } + items[i].name, resources[rindex]); + } } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { @@ -353,33 +352,33 @@ void save_resource(int type, struct res_items *items, int pass) */ if (pass == 2) { switch (type) { - /* Resources not containing a resource */ - case R_DIRECTOR: - case R_DEVICE: - case R_MSGS: - break; - - /* Resources containing a resource */ - case R_STORAGE: - if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) { + /* Resources not containing a resource */ + case R_DIRECTOR: + case R_DEVICE: + case R_MSGS: + break; + + /* Resources containing a resource */ + case R_STORAGE: + if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) { Emsg1(M_ABORT, 0, "Cannot find Storage resource %s\n", res_all.res_dir.hdr.name); - } - res->res_store.messages = res_all.res_store.messages; - break; - default: + } + res->res_store.messages = res_all.res_store.messages; + break; + default: printf("Unknown resource type %d\n", type); - error = 1; - break; + error = 1; + break; } if (res_all.res_dir.hdr.name) { - free(res_all.res_dir.hdr.name); - res_all.res_dir.hdr.name = NULL; + free(res_all.res_dir.hdr.name); + res_all.res_dir.hdr.name = NULL; } if (res_all.res_dir.hdr.desc) { - free(res_all.res_dir.hdr.desc); - res_all.res_dir.hdr.desc = NULL; + free(res_all.res_dir.hdr.desc); + res_all.res_dir.hdr.desc = NULL; } return; } @@ -387,42 +386,42 @@ void save_resource(int type, struct res_items *items, int pass) /* The following code is only executed on pass 1 */ switch (type) { case R_DIRECTOR: - size = sizeof(DIRRES); - break; + size = sizeof(DIRRES); + break; case R_STORAGE: - size = sizeof(STORES); - break; + size = sizeof(STORES); + break; case R_DEVICE: - size = sizeof(DEVRES); - break; + size = sizeof(DEVRES); + break; case R_MSGS: - size = sizeof(MSGS); - break; + size = sizeof(MSGS); + break; default: printf("Unknown resource type %d\n", type); - error = 1; - size = 1; - break; + error = 1; + size = 1; + break; } /* Common */ if (!error) { res = (URES *)malloc(size); memcpy(res, &res_all, size); if (!resources[rindex].res_head) { - resources[rindex].res_head = (RES *)res; /* store first entry */ + resources[rindex].res_head = (RES *)res; /* store first entry */ } else { - RES *next; - /* Add new res to end of chain */ - for (next=resources[rindex].res_head; next->next; next=next->next) { - if (strcmp(next->name, res->res_dir.hdr.name) == 0) { - Emsg2(M_ERROR_TERM, 0, + RES *next; + /* Add new res to end of chain */ + for (next=resources[rindex].res_head; next->next; next=next->next) { + if (strcmp(next->name, res->res_dir.hdr.name) == 0) { + Emsg2(M_ERROR_TERM, 0, _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), - resources[rindex].name, res->res_dir.hdr.name); - } - } - next->next = (RES *)res; + resources[rindex].name, res->res_dir.hdr.name); + } + } + next->next = (RES *)res; Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), - res->res_dir.hdr.name); + res->res_dir.hdr.name); } } } diff --git a/bacula/src/win32/compat/winconfig.h b/bacula/src/win32/compat/winconfig.h index e439f645fc..79b784785c 100644 --- a/bacula/src/win32/compat/winconfig.h +++ b/bacula/src/win32/compat/winconfig.h @@ -1,5 +1,8 @@ -/* src/config.h. Generated by configure. */ -/* autoconf/config.h.in. Generated from autoconf/configure.in by autoheader. */ +/* + * This file was originally generated by configure, but has been edited + * to provide the correct defines for the Native Win32 build under + * Visual Studio. + */ /* ------------------------------------------------------------------------- */ /* -- CONFIGURE SPECIFIED FEATURES -- */ /* ------------------------------------------------------------------------- */ diff --git a/bacula/src/win32/compat/winhost.h b/bacula/src/win32/compat/winhost.h index 4fe7307591..9fc81dca83 100644 --- a/bacula/src/win32/compat/winhost.h +++ b/bacula/src/win32/compat/winhost.h @@ -5,7 +5,7 @@ * */ /* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + Copyright (C) 2000-2004 Kern Sibbald and John Walker This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as -- 2.39.5