fixes for BSDI. see ChangeLog.
authorNathan Bryant <loanshark@uncensored.citadel.org>
Wed, 24 Feb 1999 13:54:18 +0000 (13:54 +0000)
committerNathan Bryant <loanshark@uncensored.citadel.org>
Wed, 24 Feb 1999 13:54:18 +0000 (13:54 +0000)
citadel/ChangeLog
citadel/Makefile.in
citadel/acconfig.h
citadel/configure.in
citadel/database.c
citadel/getutline.c
citadel/housekeeping.c
citadel/mime_parser.c
citadel/msgbase.c
citadel/routines.c
citadel/sysdep.c

index fb6b6ecceadfb36e03b973f3eaa50812607c6024..cd1eac629a50570aa121a6a31697532b9f980651 100644 (file)
@@ -1,3 +1,19 @@
+1999-02-24 Nathan Bryant <bryant@cs.usm.maine.edu>
+       * configure.in: improved check for pthreads
+       * configure.in, routines.c, acconfig.h: check for ut_type in struct utmp
+       * configure.in, Makefile.in: support for building server modules as
+         relocatable objects for BSDI (which still uses a.out *gag* *choke*)
+       * configure.in: compiler choice & flags for BSDI; check for libtermcap
+       * database.c: don't use a critical section in open_databases()
+       * housekeeping.c: use getfloor()/putfloor() instead of
+         lgetfloor()/lputfloor() in check_ref_counts()
+       * mime_parser.c: include <errno.h>
+       * msgbase.c: include <limits.h>
+       * sysdep.c: hacks for BSDI. use signals to fake thread cancellation;
+         don't call master_cleanup() directly from signal handler.
+       * routines.c: prototype getutline() if necessary
+       * getutline.c: stupid bugfix
+
 Mon Feb 15 22:59:00 EST 1999 Vaggelis Tsirkas
        * citadel.c: increased hostname buffer size to handle very big names
 
index 2d49e91a2045cad809f292459f1bc975cd176849..e2720353dcc0f760dbb65725f2ad5042dafce741 100644 (file)
@@ -19,11 +19,12 @@ all: $(TARGETS)
 .SUFFIXES: .ro .mo .d
 
 SUFFIX=@SUFFIX@
+SO=@SO@
 
 CLIENT_TARGETS=citadel$(SUFFIX) whobbs$(SUFFIX)
 SERVER_TARGETS=citserver setup
-SERV_MODULES=modules/serv_chat.so \
-       modules/serv_upgrade.so modules/serv_expire.so
+SERV_MODULES=modules/serv_chat$(SO) \
+       modules/serv_upgrade$(SO) modules/serv_expire$(SO)
 UTIL_TARGETS=aidepost netmailer netproc netsetup msgform readlog rcit \
        stats citmail netpoll mailinglist userlist sendcommand \
        base64 qpdecode
@@ -109,18 +110,30 @@ citserver: citserver.ro user_ops.ro support.ro room_ops.ro file_ops.ro \
 modules/serv_chat.so: serv_chat.mo
        $(CC) -shared -o modules/serv_chat.so serv_chat.mo
 
+modules/serv_chat.mo: serv_chat.mo
+       ln -f serv_chat.mo modules
+
 .c.mo:
        $(CC) $(CFLAGS) $(CPPFLAGS) $(DEFS) $(PTHREAD_DEFS) $(PICFLAGS) -DPIC -c $< -o $@
 
 modules/serv_test.so: serv_test.mo
        $(CC) -shared -o modules/serv_test.so serv_test.mo
 
+modules/serv_test.mo: serv_test.mo
+       ln -f serv_test.mo modules
+
 modules/serv_upgrade.so: serv_upgrade.mo
        $(CC) -shared -o modules/serv_upgrade.so serv_upgrade.mo
 
+modules/serv_upgrade.mo: serv_upgrade.mo
+       ln -f serv_upgrade.mo modules
+
 modules/serv_expire.so: serv_expire.mo
        $(CC) -shared -o modules/serv_expire.so serv_expire.mo
 
+modules/serv_expire.mo: serv_expire.mo
+       ln -f serv_expire.mo modules
+
 aidepost: aidepost.o config.o $(LIBOBJS)
        $(CC) aidepost.o config.o $(LIBOBJS) $(LDFLAGS) -o aidepost
 
index 7c4fdb60687f942d3e18e1a97a7b7c26f32287a8..64357ff50ef1042261b67c37d363399addf62206 100644 (file)
@@ -3,3 +3,6 @@
 
 /* define this to enable the autologin feature */
 #undef ENABLE_AUTOLOGIN
+
+/* define this if struct utmp has an ut_type member */
+#undef HAVE_UT_TYPE
index 7b7bcaae914b4657ef7bc92696edff39b0eeb0a5..4ef211456ad491c1875fb0863acdf7848996bdd1 100644 (file)
@@ -15,16 +15,20 @@ dnl By default, we only build the client (citadel and whobbs) unless we can
 dnl figure out how to build with POSIX threads.
 TARGETS=client
 
-dnl Check for Digital Unix: it has a different way of building for pthreads,
-dnl and we can't build pthreads programs with gcc due to header problems.
 AC_CANONICAL_HOST
+SO=.so
 case "$host" in
+       dnl BSDI 3.0 wants relocatable object modules instead of shared libs
+       dnl for dlopen(), and has a wrapper script to link with shared libs
+       i?86-*-bsdi*)
+               test -z "$CC" -a -x /usr/bin/shlicc2 && CC=shlicc2
+               SO=.mo
+       ;;
+       dnl Digital Unix has an odd way to build pthreads, and we can't build
+       dnl pthreads programs with gcc due to header problems.
        alpha*-dec-osf*)
-               if test -z "$CC"; then
-                       CC=cc
-               fi
+               test -z "$CC" && CC=cc
                SERVER_LDFLAGS=-pthread
-               TARGETS="client server utils serv_modules"
        ;;
        *-*-cygwin32)
                SUFFIX=.exe
@@ -33,18 +37,21 @@ esac
 
 dnl Checks for programs.
 AC_PROG_CC
+
+dnl Set up system-dependent compiler flags.
 if test "$GCC" = yes; then
        CFLAGS="$CFLAGS -Wall -Wstrict-prototypes"
-       dnl pass -rdynamic to the linker to enable dlopen() modules to
-       dnl refer to symbols in the main executable (applies to citserver)
        case "$host" in
+               i?86-*-bsdi*)
+               ;;
                mips*-sgi-irix*)
+                       PICFLAGS=-fPIC
                ;;
                *)
                        SERVER_LDFLAGS=-rdynamic
+                       PICFLAGS=-fPIC
                ;;
        esac
-       PICFLAGS=-fPIC
 fi
 AC_PROG_RANLIB
 AC_PROG_INSTALL
@@ -79,16 +86,18 @@ if test "$ac_cv_func_dlopen" = no; then
 fi
 
 AC_CHECK_LIB(gdbm, gdbm_open)
-AC_CHECK_LIB(curses, initscr, CURSES=-lcurses)
+
+save_LIBS=$LIBS
+AC_CHECK_LIB(termcap, tgetent, [LIBS="$LIBS -ltermcap"
+       CURSES=-ltermcap])
+AC_CHECK_LIB(curses, initscr, CURSES="-lcurses $CURSES")
+LIBS=$save_LIBS
 
 dnl Check for libpthread(s) if we're not using Digital UNIX. (On which the
-dnl -pthread flag takes care of this.) If we find one of the libraries, then
-dnl set up the TARGETS variable to build the server as well as the client.
+dnl -pthread flag takes care of this.)
 if test "$SERVER_LDFLAGS" != -pthread; then
-       AC_CHECK_LIB(pthread, pthread_create, [LIBS="$LIBS -lpthread"
-               TARGETS="client server utils serv_modules"])
-       AC_CHECK_LIB(pthreads, pthread_create, [LIBS="$LIBS -lpthreads"
-               TARGETS="client server utils serv_modules"])
+       AC_CHECK_LIB(pthread, pthread_create)
+       AC_CHECK_LIB(pthreads, pthread_create)
 fi
 
 dnl Checks for header files.
@@ -104,15 +113,24 @@ AC_TYPE_SIZE_T
 AC_HEADER_TIME
 AC_STRUCT_TM
 
+AC_CACHE_CHECK([for ut_type in struct utmp], ac_cv_struct_ut_type,
+[AC_TRY_COMPILE([#include <utmp.h>], [struct utmp ut; ut.ut_type;],
+ac_cv_struct_ut_type=yes, ac_cv_struct_ut_type=no)])
+if test $ac_cv_struct_ut_type = yes; then
+       AC_DEFINE(HAVE_UT_TYPE)
+fi
+
 dnl Checks for library functions.
 AC_FUNC_GETPGRP
 AC_PROG_GCC_TRADITIONAL
 AC_TYPE_SIGNAL
 AC_FUNC_VPRINTF
-AC_CHECK_FUNCS(mkdir mkfifo mktime rmdir select socket strerror)
+AC_CHECK_FUNCS(mkdir mkfifo mktime pthread_cancel rmdir select socket strerror)
+AC_CHECK_FUNC(pthread_create, TARGETS="client server utils serv_modules")
 AC_REPLACE_FUNCS(snprintf getutline)
 
 dnl Done! Now write the Makefile and sysdep.h
+AC_SUBST(SO)
 AC_SUBST(CURSES)
 AC_SUBST(TARGETS)
 AC_SUBST(SERVER_LDFLAGS)
index 1945f36631cc7e1dafe2d19e6a4922645ce55cf6..ad91ccec1000f6e0689f0769f1ec241dfa0d586d 100644 (file)
@@ -99,8 +99,13 @@ void open_databases(void) {
         */
        system("exec mkdir data 2>/dev/null");
 
+       /* a critical section is unnecessary, as this function is called before
+          any other threads are created. and it causes problems on BSDI.
+
        begin_critical_section(S_DATABASE);
 
+        */
+
        gdbms[CDB_MSGMAIN] = gdbm_open("data/msgmain.gdbm", 8192,
                GDBM_WRCREAT, 0600, NULL);
        if (gdbms[CDB_MSGMAIN] == NULL) {
@@ -148,7 +153,9 @@ void open_databases(void) {
                dtkey[a].dptr = NULL;
                }
 
+       /*
        end_critical_section(S_DATABASE);
+        */
 
        }
 
index 0398b8ff6babee532b08c02c87bbc987ec949da8..a567b90132fc954b92d57213f89ebd3c6213e26d 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <utmp.h>
 #include <paths.h>
+#include <string.h>
 
 struct utmp *getutline(struct utmp *ut)
 {
@@ -25,7 +26,7 @@ struct utmp *getutline(struct utmp *ut)
        fclose(utmp);
        return NULL;
       }
-  while (ut->ut_line != retval.ut_line);
+  while (strcmp(ut->ut_line, retval.ut_line));
 
   fclose(utmp);
   return &retval;
index a97ea47799e35c7c7ee824da1ca1dc40397aae44..d273298b82b697aed007029f2d239918a1555da9 100644 (file)
@@ -97,10 +97,10 @@ void do_housekeeping(void) {
 void check_ref_counts_backend(struct quickroom *qrbuf) {
        struct floor flbuf;
 
-       lgetfloor(&flbuf, qrbuf->QRfloor);
+       getfloor(&flbuf, qrbuf->QRfloor);
        ++flbuf.f_ref_count;
        flbuf.f_flags = flbuf.f_flags | QR_INUSE;
-       lputfloor(&flbuf, qrbuf->QRfloor);
+       putfloor(&flbuf, qrbuf->QRfloor);
        }
 
 void check_ref_counts(void) {
@@ -108,10 +108,10 @@ void check_ref_counts(void) {
        int a;
 
        for (a=0; a<MAXFLOORS; ++a) {
-               lgetfloor(&flbuf, a);
+               getfloor(&flbuf, a);
                flbuf.f_ref_count = 0;
                flbuf.f_flags = flbuf.f_flags & ~QR_INUSE;
-               lputfloor(&flbuf, a);
+               putfloor(&flbuf, a);
                }
 
        ForEachRoom(check_ref_counts_backend);
index 9b35dc0822588e1cbbdadeb59f3937ec09193134..bc046ba8e27c963c7f2aeeadaacbade62fade08d 100644 (file)
@@ -18,6 +18,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <errno.h>
 #ifdef HAVE_PTHREAD_H
 #include <pthread.h>
 #endif
index 30bef3025ca24c8416a57fd7152e3bb6f5f6393d..d1b585a18fb1117a6ee3f3c14dce7c7273156f24 100644 (file)
@@ -11,6 +11,7 @@
 #ifdef HAVE_PTHREAD_H
 #include <pthread.h>
 #endif
+#include <limits.h>
 #include "citadel.h"
 #include "server.h"
 #include <errno.h>
index 24ad833dd271ab108404e22a56b437e25c68d40b..8a0790923fcb73f0a409d17ea5216d10bee29749 100644 (file)
 #include <utmp.h>
 #endif
 
+#ifndef HAVE_GETUTLINE
+struct utmp *getutline(struct utmp *ut);
+#endif
+
 #define ROUTINES_C
 
 #include "citadel.h"
@@ -447,14 +451,18 @@ void locate_host(char *hbuf)
        if ((put = getutline(&ut)) == NULL)
                goto fail;
 
+#ifdef HAVE_UT_TYPE
        if (put->ut_type == USER_PROCESS) {
+#endif
                if (*put->ut_host)
                        safestrncpy(hbuf, put->ut_host, 24);
                else
                        safestrncpy(hbuf, put->ut_line, 24);
+#ifdef HAVE_UT_TYPE
                }
        else goto fail;
 #endif
+#endif /* HAVE_UTMP_H */
        }
 
 /*
index 69bc573a8929eeceec14c11e141993a129a88899..ad4c59037f2a45f3ec679a4147a45af99ecea958 100644 (file)
@@ -154,6 +154,33 @@ void dump_tracked() {
        }
 #endif
 
+#ifndef HAVE_PTHREAD_CANCEL
+/*
+ * signal handler to fake thread cancellation; only required on BSDI as far
+ * as I know.
+ */
+
+static pthread_t main_thread_id;
+
+static RETSIGTYPE cancel_thread(int signum) {
+       pthread_exit(NULL);
+       }
+#endif
+
+/*
+ * we used to use master_cleanup() as a signal handler to shut down the server.
+ * however, master_cleanup() and the functions it calls do some things that
+ * aren't such a good idea to do from a signal handler: acquiring mutexes,
+ * playing with signal masks on BSDI systems, etc. so instead we install the
+ * following signal handler to set a global variable to inform the main loop
+ * that it's time to call master_cleanup() and exit.
+ */
+
+static volatile int time_to_die = 0;
+
+static RETSIGTYPE signal_cleanup(int signum) {
+       time_to_die = 1;
+       }
 
 
 /*
@@ -178,13 +205,17 @@ void init_sysdep(void) {
 
        /*
         * The action for unexpected signals and exceptions should be to
-        * call master_cleanup() to gracefully shut down the server.
+        * call signal_cleanup() to gracefully shut down the server.
         */
-       signal(SIGINT, (void(*)(int))master_cleanup);
-       signal(SIGQUIT, (void(*)(int))master_cleanup);
-       signal(SIGHUP, (void(*)(int))master_cleanup);
-       signal(SIGTERM, (void(*)(int))master_cleanup);
+       signal(SIGINT, signal_cleanup);
+       signal(SIGQUIT, signal_cleanup);
+       signal(SIGHUP, signal_cleanup);
+       signal(SIGTERM, signal_cleanup);
        signal(SIGPIPE, SIG_IGN);
+#ifndef HAVE_PTHREAD_CANCEL /* fake it - only BSDI afaik */
+       main_thread_id = pthread_self();
+       signal(SIGUSR1, cancel_thread);
+#endif
        }
 
 
@@ -193,12 +224,26 @@ void init_sysdep(void) {
  */
 void begin_critical_section(int which_one)
 {
+#ifdef HAVE_PTHREAD_CANCEL
        int oldval;
+#else
+       sigset_t set;
+#endif
 
        /* lprintf(8, "begin_critical_section(%d)\n", which_one); */
 
+#ifdef HAVE_PTHREAD_CANCEL
        /* Don't get interrupted during the critical section */
        pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldval);
+#else
+       /* We're faking cancellation with signals. Block SIGUSR1 while we're in
+        * the critical section. */
+       if (!pthread_equal(pthread_self(), main_thread_id)) {
+               sigemptyset(&set);
+               sigaddset(&set, SIGUSR1);
+               pthread_sigmask(SIG_BLOCK, &set, NULL);
+               }
+#endif
 
        /* Obtain a semaphore */
        pthread_mutex_lock(&Critters[which_one]);
@@ -210,19 +255,33 @@ void begin_critical_section(int which_one)
  */
 void end_critical_section(int which_one)
 {
+#ifdef HAVE_PTHREAD_CANCEL
        int oldval;
+#else
+       sigset_t set;
+#endif
 
        /* lprintf(8, "  end_critical_section(%d)\n", which_one); */
 
        /* Let go of the semaphore */
        pthread_mutex_unlock(&Critters[which_one]);
 
+#ifdef HAVE_PTHREAD_CANCEL
        /* If a cancel was sent during the critical section, do it now.
         * Then re-enable thread cancellation.
         */
        pthread_testcancel();
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldval);
        pthread_testcancel();
+#else
+       /* We're faking it. Unblock SIGUSR1; signals sent during the critical
+        * section should now be able to kill us. */
+       if (!pthread_equal(pthread_self(), main_thread_id)) {
+               sigemptyset(&set);
+               sigaddset(&set, SIGUSR1);
+               pthread_sigmask(SIG_UNBLOCK, &set, NULL);
+               }
+#endif
 
        }
 
@@ -332,11 +391,15 @@ struct CitContext *CreateNewContext(void) {
  */
 void InitMyContext(struct CitContext *con)
 {
+#ifdef HAVE_PTHREAD_CANCEL
        int oldval;
+#endif
 
        con->mythread = pthread_self();
+#ifdef HAVE_PTHREAD_CANCEL
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldval);
        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldval);
+#endif
        if (pthread_setspecific(MyConKey, (void *)con) != 0) {
                lprintf(1, "ERROR!  pthread_setspecific() failed: %s\n",
                        strerror(errno));
@@ -568,8 +631,12 @@ void kill_session(int session_to_kill) {
        lprintf(9, "kill_session() finished scanning.\n");
 
        if (killme != 0) {
+#ifdef HAVE_PTHREAD_CANCEL
                lprintf(9, "calling pthread_cancel()\n");
                pthread_cancel(killme);
+#else
+               pthread_kill(killme, SIGUSR1);
+#endif
                }
        }
 
@@ -709,6 +776,8 @@ int main(int argc, char **argv)
        char tracefile[128];            /* Name of file to log traces to */
        int a, i;                       /* General-purpose variables */
        char convbuf[128];
+       fd_set readfds;
+       struct timeval tv;
         
        /* specify default port name and trace file */
        strcpy(tracefile, "");
@@ -792,7 +861,17 @@ int main(int argc, char **argv)
         * Endless loop.  Listen on the master socket.  When a connection
         * comes in, create a socket, a context, and a thread.
         */     
-       while (1) {
+       while (!time_to_die) {
+               /* we need to check if a signal has been delivered. because
+                * syscalls may be restartable across signals, we call
+                * select with a timeout of 1 second and repeatedly check for
+                * time_to_die... */
+               FD_ZERO(&readfds);
+               FD_SET(msock, &readfds);
+               tv.tv_sec = 1;
+               tv.tv_usec = 0;
+               if (select(msock + 1, &readfds, NULL, NULL, &tv) <= 0)
+                       continue;
                alen = sizeof fsin;
                ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
                if (ssock < 0) {
@@ -839,5 +918,7 @@ int main(int argc, char **argv)
                        lprintf(9, "done!\n");
                        }
                }
+       master_cleanup();
+       return 0;
        }