From 49a5e4f534603eb5f17111d591a00812d06fbd90 Mon Sep 17 00:00:00 2001 From: Nathan Bryant Date: Wed, 24 Feb 1999 13:54:18 +0000 Subject: [PATCH] fixes for BSDI. see ChangeLog. --- citadel/ChangeLog | 16 ++++++++ citadel/Makefile.in | 17 +++++++- citadel/acconfig.h | 3 ++ citadel/configure.in | 52 +++++++++++++++-------- citadel/database.c | 7 ++++ citadel/getutline.c | 3 +- citadel/housekeeping.c | 8 ++-- citadel/mime_parser.c | 1 + citadel/msgbase.c | 1 + citadel/routines.c | 8 ++++ citadel/sysdep.c | 93 +++++++++++++++++++++++++++++++++++++++--- 11 files changed, 179 insertions(+), 30 deletions(-) diff --git a/citadel/ChangeLog b/citadel/ChangeLog index fb6b6ecce..cd1eac629 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -1,3 +1,19 @@ +1999-02-24 Nathan Bryant + * 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 + * msgbase.c: include + * 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 diff --git a/citadel/Makefile.in b/citadel/Makefile.in index 2d49e91a2..e2720353d 100644 --- a/citadel/Makefile.in +++ b/citadel/Makefile.in @@ -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 diff --git a/citadel/acconfig.h b/citadel/acconfig.h index 7c4fdb606..64357ff50 100644 --- a/citadel/acconfig.h +++ b/citadel/acconfig.h @@ -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 diff --git a/citadel/configure.in b/citadel/configure.in index 7b7bcaae9..4ef211456 100644 --- a/citadel/configure.in +++ b/citadel/configure.in @@ -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 ], [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) diff --git a/citadel/database.c b/citadel/database.c index 1945f3663..ad91ccec1 100644 --- a/citadel/database.c +++ b/citadel/database.c @@ -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); + */ } diff --git a/citadel/getutline.c b/citadel/getutline.c index 0398b8ff6..a567b9013 100644 --- a/citadel/getutline.c +++ b/citadel/getutline.c @@ -10,6 +10,7 @@ #include #include #include +#include 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; diff --git a/citadel/housekeeping.c b/citadel/housekeeping.c index a97ea4779..d273298b8 100644 --- a/citadel/housekeeping.c +++ b/citadel/housekeeping.c @@ -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 #include #include +#include #ifdef HAVE_PTHREAD_H #include #endif diff --git a/citadel/msgbase.c b/citadel/msgbase.c index 30bef3025..d1b585a18 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -11,6 +11,7 @@ #ifdef HAVE_PTHREAD_H #include #endif +#include #include "citadel.h" #include "server.h" #include diff --git a/citadel/routines.c b/citadel/routines.c index 24ad833dd..8a0790923 100644 --- a/citadel/routines.c +++ b/citadel/routines.c @@ -20,6 +20,10 @@ #include #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 */ } /* diff --git a/citadel/sysdep.c b/citadel/sysdep.c index 69bc573a8..ad4c59037 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -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; } -- 2.30.2