]> git.sur5r.net Git - bacula/bacula/commitdiff
Start SIGHUP coding + misc
authorKern Sibbald <kern@sibbald.com>
Sat, 21 Feb 2004 11:50:34 +0000 (11:50 +0000)
committerKern Sibbald <kern@sibbald.com>
Sat, 21 Feb 2004 11:50:34 +0000 (11:50 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1063 91ce42f0-d328-0410-95d8-f526ca767f89

24 files changed:
bacula/ChangeLog
bacula/autoconf/configure.in
bacula/kernstodo
bacula/platforms/suse/bacula-dir.in
bacula/platforms/suse/bacula-fd.in
bacula/platforms/suse/bacula-sd.in
bacula/platforms/suse/bacula.in [new file with mode: 0644]
bacula/projects [new file with mode: 0644]
bacula/src/baconfig.h
bacula/src/cats/sql_list.c
bacula/src/console/console_conf.c
bacula/src/dird/dird.c
bacula/src/dird/dird_conf.c
bacula/src/dird/ua_output.c
bacula/src/filed/filed_conf.c
bacula/src/findlib/makepath.c
bacula/src/gnome2-console/console_conf.c
bacula/src/lib/parse_conf.c
bacula/src/lib/parse_conf.h
bacula/src/lib/rwlock.c
bacula/src/stored/bacula-sd.conf.in
bacula/src/stored/stored_conf.c
bacula/src/win32/compat/winconfig.h
bacula/src/win32/compat/winhost.h

index 639ac1bce537af02f465ba420b0c7b5037bc4798..269225cf7c115718a5ed41d61398289b4077e0fc 100644 (file)
@@ -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.
index a2362513cc1ba82c793d7b742958d832abd7334b..667dac318d7a8fdacc208af3f5456671ead6f5bc 100644 (file)
@@ -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)
index 0898d3eba97ec4c1253f92bf3ee568e40d89f26a..8a4831ec00ed75cc6e4ab2fb1661b3aa23936276 100644 (file)
@@ -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
index d7a2ea7956cc9d262729209842f552f1b2cc9d3e..d192063b68cbcd4b6921e89e02dc918a9cd81d76 100755 (executable)
@@ -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
 #
index 72b0cecca659b4eb050d24da4bc13f5d11661205..ba270866c2aa4d8d989142743b4dab85960dab57 100755 (executable)
@@ -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.
 #
index d79d9e7a5ec1d09855d3764bab8f418bde945e62..1c7013f27d240686063e39b20232bccb97808cc2 100755 (executable)
@@ -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 (file)
index 0000000..832ec05
--- /dev/null
@@ -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 <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
diff --git a/bacula/projects b/bacula/projects
new file mode 100644 (file)
index 0000000..8489863
--- /dev/null
@@ -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
index eebeea0dc42b9744bade3ce3051e4c07d956a574..35698e8c1d10f389ab7f6e5e2e038fa3499324d3 100644 (file)
@@ -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
index 4edbdddd579aff1922df5e8ae540fd7fd3fcf3ff..428e4ae8fd766ea8b3fb3e72f61acb6944bc8193 100644 (file)
@@ -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);
index daeebc898b0d48ac832335896187e71524143a0f..9def2192791c5ce1d6656bc313f687a254e033c0 100644 (file)
@@ -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 */
 
index 8842bc62677abd99767c82b57b15c6959b17cec3..6fb1cd4e28b8d9bb609d2295ff3175a79d55bd51 100644 (file)
@@ -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;
 }
 
 /*
index ebea539c103a9fe523509e4eca9f661ec15e777e..d567a3bbf3f1fa4f4f06bd49a0dfa7edc3193e7b 100644 (file)
@@ -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);
index 55d81ebb9ce71788e67e59366cad9260cc34e58f..d8417e4370eda1af87795f94aea10681cc0bb1ec 100644 (file)
@@ -108,6 +108,7 @@ int show_cmd(UAContext *ua, char *cmd)
    Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
 
 
+   LockRes();
    for (i=1; i<ua->argc; 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;
 }
 
index 8767ad3733b5ccdd6c31cba56a400a5ec1dd8957..4c37767bb2c55a054d5a8dd405eb90e01e4c4ed4 100644 (file)
@@ -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);
       }
    }
 }
index bc1fb33989832a95d368f34aa801a4c931492cc6..2932b83e4aaad665b72eb2c26c966fd7901857b2 100644 (file)
@@ -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;
       }
 
index 5c798a04b0253aa5ea18e436bc241f205d7dfcc1..6c89c3a73a19a4150a565b717c4ef3846a745f30 100644 (file)
@@ -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 */
 
index b21560d6283c4f332398b02ceb79ae2f7e59ce02..642fac588afba687dddbd2bd7e7fcdff09a6f7a2 100755 (executable)
@@ -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;
    }
 }
index fe4be0fc048f0e926f62b96f96c6a78eec70b7bb..d216e49e2f6d7e9de82a214bf67d6e5732ec5fb1 100644 (file)
@@ -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);
index 6729a31ca13e1a6eba6dba399099097ddc324bf0..f6912b519de5eac9632687353607cabc47dd1706 100644 (file)
@@ -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) {
index 3cb2fcf5138acb90ca8863a3e3cde702222fa269..c4e6bd8c2f3bc89d385cae38c53c6100c7a40f14 100644 (file)
@@ -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
 #}
  
 
index 206b0cb4416b758e69ff68b97b5cb3784ea9e5b8..459a7d91d229137c91a7542dfc3a9a44bf344fb9 100644 (file)
@@ -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);
       }
    }
 }
index e439f645fc4f3ce9a91bdc0b822b10dbc9609f87..79b784785c2ad5d709a3c71e812c6586f7d767ea 100644 (file)
@@ -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                    -- */
 /* ------------------------------------------------------------------------- */
index 4fe730759139b6f810d123eda1917763e233ac4d..9fc81dca832d7b8ae2e7bb115ddd0c0624511f33 100644 (file)
@@ -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