+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.
platforms/suse/bacula-fd \
platforms/suse/bacula-sd \
platforms/suse/bacula-dir \
+ platforms/suse/bacula \
platforms/suse/bacula.spec"
;;
suse5)
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
#! /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
#
# 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.
#
#! /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.
#
--- /dev/null
+#! /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 <volker@volker-sauer.de> 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
--- /dev/null
+
+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
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
"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,"
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);
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);
*/
int r_first = R_FIRST;
int r_last = R_LAST;
-pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Forward referenced subroutines */
drop(uid, gid); /* reduce priveleges if requested */
-/* signal(SIGHUP, reload_config); */
+ signal(SIGHUP, reload_config);
init_console_msg(working_directory);
*/
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 */
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);
}
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;
}
/*
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);
Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
+ LockRes();
for (i=1; i<ua->argc; i++) {
type = 0;
res_name = ua->argk[i];
break;
}
}
+
} else {
/* Dump a single resource with specified name */
recurse = 0;
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;
}
* 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
*
*/
int r_first = R_FIRST;
int r_last = R_LAST;
-pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Forward referenced subroutines */
{"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}
};
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);
}
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);
}
*/
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 (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;
}
/* 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);
}
}
}
/* 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;
}
*/
int r_first = R_FIRST;
int r_last = R_LAST;
-pthread_mutex_t res_mutex = PTHREAD_MUTEX_INITIALIZER;
/* Forward referenced subroutines */
*/
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
#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);
{
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;
}
+/* #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));
+ }
}
/*
int i;
for (i=r_first; i<=r_last; i++) {
free_resource(i);
+ resources[i-r_first].res_head = NULL;
}
}
/* 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);
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);
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) {
# 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
#}
/* 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 */
{"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}
};
return;
}
sendit(sock, "dump_resource type=%d\n", type);
- if (type < 0) { /* no recursion */
+ if (type < 0) { /* no recursion */
type = - type;
recurse = 0;
}
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));
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) {
*/
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) {
*/
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;
}
/* 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);
}
}
}
-/* 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 -- */
/* ------------------------------------------------------------------------- */
*
*/
/*
- 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