+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
.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
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
/* define this to enable the autologin feature */
#undef ENABLE_AUTOLOGIN
+
+/* define this if struct utmp has an ut_type member */
+#undef HAVE_UT_TYPE
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
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
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.
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)
*/
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) {
dtkey[a].dptr = NULL;
}
+ /*
end_critical_section(S_DATABASE);
+ */
}
#include <stdio.h>
#include <utmp.h>
#include <paths.h>
+#include <string.h>
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;
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) {
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);
#include <ctype.h>
#include <string.h>
#include <sys/stat.h>
+#include <errno.h>
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
+#include <limits.h>
#include "citadel.h"
#include "server.h"
#include <errno.h>
#include <utmp.h>
#endif
+#ifndef HAVE_GETUTLINE
+struct utmp *getutline(struct utmp *ut);
+#endif
+
#define ROUTINES_C
#include "citadel.h"
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 */
}
/*
}
#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;
+ }
/*
/*
* 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
}
*/
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]);
*/
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
}
*/
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));
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
}
}
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, "");
* 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) {
lprintf(9, "done!\n");
}
}
+ master_cleanup();
+ return 0;
}