diff --git a/src/sbbs3/GNUmakefile b/src/sbbs3/GNUmakefile
index a7925c285503f5496806390d3ef01dcc090b3f04..9deeed98ba914eba06f83d47bba6c8fc32932ac6 100644
--- a/src/sbbs3/GNUmakefile
+++ b/src/sbbs3/GNUmakefile
@@ -60,6 +60,10 @@ ifeq ($(os),linux)
   CFLAGS += -DUSE_LINUX_CAPS
   CON_LIBS += -lcap
  endif
+ ifeq ($(shell test -f /usr/include/systemd/sd-daemon.h && echo "yes"),yes)
+  CFLAGS += -DUSE_SYSTEMD
+  CON_LIBS += -lsystemd
+ endif
 endif
 
 include sbbsdefs.mk
diff --git a/src/sbbs3/ftpsrvr.c b/src/sbbs3/ftpsrvr.c
index d21bb37955d72078e18af132ea32dcb01b96a1c4..070a56933db97f5d4bb6dc7e9657a98d1c5cdd45 100644
--- a/src/sbbs3/ftpsrvr.c
+++ b/src/sbbs3/ftpsrvr.c
@@ -192,10 +192,10 @@ static char* server_host_name(void)
 	return startup->host_name[0] ? startup->host_name : scfg.sys_inetaddr;
 }
 
-static void status(char* str)
+static void set_state(enum server_state state)
 {
-	if(startup!=NULL && startup->status!=NULL)
-	    startup->status(startup->cbdata,str);
+	if(startup != NULL && startup->set_state != NULL)
+		startup->set_state(startup->cbdata, state);
 }
 
 static void update_clients(void)
@@ -4803,8 +4803,6 @@ static void ctrl_thread(void* arg)
 		PlaySound(startup->sound.hangup, NULL, SND_ASYNC|SND_FILENAME);
 #endif
 
-/*	status(STATUS_WFC); server thread should control status display */
-
 	if(pasv_sock!=INVALID_SOCKET)
 		ftp_close_socket(&pasv_sock,&pasv_sess,__LINE__);
 	if(data_sock!=INVALID_SOCKET)
@@ -4873,7 +4871,6 @@ static void cleanup(int code, int line)
 #endif
 
 	thread_down();
-	status("Down");
 	if(terminate_server || code)
 		lprintf(LOG_INFO,"#### FTP Server thread terminated (%lu clients served)", served);
 	if(startup!=NULL && startup->terminated!=NULL)
@@ -4941,6 +4938,7 @@ void ftp_server(void* arg)
 		fprintf(stderr, "Invalid startup structure!\n");
 		return;
 	}
+	set_state(SERVER_INIT);
 
 	uptime=0;
 	served=0;
@@ -4963,8 +4961,6 @@ void ftp_server(void* arg)
 		(void)protected_uint32_adjust(&thread_count,1);
 		thread_up(FALSE /* setuid */);
 
-		status("Initializing");
-
 		memset(&scfg, 0, sizeof(scfg));
 
 		lprintf(LOG_INFO,"Synchronet FTP Server Version %s%c%s"
@@ -5068,8 +5064,6 @@ void ftp_server(void* arg)
 		 */
 		xpms_add_list(ftp_set, PF_UNSPEC, SOCK_STREAM, 0, startup->interfaces, startup->port, "FTP Server", ftp_open_socket_cb, startup->seteuid, NULL);
 
-		status(STATUS_WFC);
-
 		/* Setup recycle/shutdown semaphore file lists */
 		shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","ftp");
 		recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","ftp");
@@ -5082,8 +5076,7 @@ void ftp_server(void* arg)
 		}
 
 		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started(startup->cbdata);
+		set_state(SERVER_READY);
 
 		lprintf(LOG_INFO,"FTP Server thread started");
 
@@ -5169,6 +5162,8 @@ void ftp_server(void* arg)
 			served++;
 		}
 
+		set_state(terminate_server ? SERVER_STOPPING : SERVER_RELOADING);
+
 #if 0 /* def _DEBUG */
 		lprintf(LOG_DEBUG,"0000 terminate_server: %d",terminate_server);
 #endif
@@ -5199,4 +5194,6 @@ void ftp_server(void* arg)
 	} while(!terminate_server);
 
 	protected_uint32_destroy(thread_count);
+
+	set_state(SERVER_STOPPED);
 }
diff --git a/src/sbbs3/ftpsrvr.h b/src/sbbs3/ftpsrvr.h
index f02bd49d0870bdd7b64c1f25d5d3c956153e1d00..91d0a6d00d8efc1a2ad463a294fe033c38f1d6ef 100644
--- a/src/sbbs3/ftpsrvr.h
+++ b/src/sbbs3/ftpsrvr.h
@@ -51,8 +51,7 @@ typedef struct {
 	/* Callbacks (NULL if unused) */
 	int 	(*lputs)(void*, int level, const char* msg);
 	void	(*errormsg)(void*, int level, const char* msg);
-	void	(*status)(void*, const char*);
-    void	(*started)(void*);
+	void	(*set_state)(void*, enum server_state);
 	void	(*recycle)(void*);
     void	(*terminated)(void*, int code);
     void	(*clients)(void*, int active);
diff --git a/src/sbbs3/mailsrvr.c b/src/sbbs3/mailsrvr.c
index 29ebda2636f0b57b66efac85688641c119c5fa73..becd4572f7b2e052ebd90631de6739c1e4ad1abb 100644
--- a/src/sbbs3/mailsrvr.c
+++ b/src/sbbs3/mailsrvr.c
@@ -244,6 +244,12 @@ static char* server_host_name(void)
 	return startup->host_name[0] ? startup->host_name : scfg.sys_inetaddr;
 }
 
+static void set_state(enum server_state state)
+{
+	if(startup != NULL && startup->set_state != NULL)
+		startup->set_state(startup->cbdata, state);
+}
+
 static void update_clients(void)
 {
 	if(startup!=NULL && startup->clients!=NULL)
@@ -331,12 +337,6 @@ int mail_close_socket(SOCKET *sock, int *sess)
 	return(result);
 }
 
-static void status(char* str)
-{
-	if(startup!=NULL && startup->status!=NULL)
-	    startup->status(startup->cbdata,str);
-}
-
 int sockprintf(SOCKET sock, const char* prot, CRYPT_SESSION sess, char *fmt, ...)
 {
 	int		len;
@@ -1155,9 +1155,6 @@ static void pop3_thread(void* arg)
 	client.usernum = 0;
 	client_on(socket,&client,FALSE /* update */);
 
-	SAFEPRINTF2(str,"%s: %s", client.protocol, host_ip);
-	status(str);
-
 	if(startup->login_attempt.throttle
 		&& (login_attempts=loginAttempts(startup->login_attempt_list, &pop3.client_addr)) > 1) {
 		lprintf(LOG_DEBUG,"%04d %s [%s] Throttling suspicious connection (%lu login attempts)"
@@ -1346,8 +1343,6 @@ static void pop3_thread(void* arg)
 
 		if(startup->options&MAIL_OPT_DEBUG_POP3)
 			lprintf(LOG_INFO,"%04d %s [%s] %s logged-in %s", socket, client.protocol, host_ip, user.alias, apop ? "via APOP":"");
-		SAFEPRINTF2(str,"%s: %s", client.protocol, user.alias);
-		status(str);
 #ifdef _WIN32
 		if(startup->sound.login[0] && !sound_muted(&scfg)) 
 			PlaySound(startup->sound.login, NULL, SND_ASYNC|SND_FILENAME);
@@ -1547,8 +1542,6 @@ static void pop3_thread(void* arg)
 			}
 			activity=TRUE;
 			if(!strnicmp(buf, "RETR ",5) || !strnicmp(buf,"TOP ",4)) {
-				SAFEPRINTF2(str,"%s: %s", client.protocol, user.alias);
-				status(str);
 
 				lines=-1;
 				p=buf+4;
@@ -1738,8 +1731,6 @@ static void pop3_thread(void* arg)
 				,socket, client.protocol, host_ip, inet_addrport(&pop3.client_addr), host_name);
 	}
 
-	status(STATUS_WFC);
-
 	/* Free up resources here */
 	if(mail!=NULL)
 		freemail(mail);
@@ -3172,9 +3163,6 @@ static void smtp_thread(void* arg)
 	client.usernum = 0;
 	client_on(socket,&client,FALSE /* update */);
 
-	SAFEPRINTF(str,"SMTP: %s",host_ip);
-	status(str);
-
 	if(startup->login_attempt.throttle
 		&& (login_attempts=loginAttempts(startup->login_attempt_list, &smtp.client_addr)) > 1) {
 		lprintf(LOG_DEBUG,"%04d %s Throttling suspicious connection from: %s (%lu login attempts)"
@@ -5037,8 +5025,6 @@ static void smtp_thread(void* arg)
 		fclose(spy);
 	js_cleanup(js_runtime, js_cx, &js_glob);
 
-	status(STATUS_WFC);
-
 	listRemoveTaggedNode(&current_logins, socket, /* free_data */TRUE);
 	(void)protected_uint32_adjust(&active_clients, -1);
 	update_clients();
@@ -5618,8 +5604,6 @@ static void sendmail_thread(void* arg)
 
 			lprintf(LOG_INFO,"0000 SEND Message #%u (%u of %u) from %s to %s"
 				,msg.hdr.number, u+1, msgs, sender_info, rcpt_info);
-			SAFEPRINTF2(str,"Sending (%u of %u)", u+1, msgs);
-			status(str);
 #ifdef _WIN32
 			if(startup->outbound_sound[0] && !sound_muted(&scfg)) 
 				PlaySound(startup->outbound_sound, NULL, SND_ASYNC|SND_FILENAME);
@@ -5874,7 +5858,6 @@ static void sendmail_thread(void* arg)
 			if(msg.from_agent==AGENT_PERSON && !(startup->options&MAIL_OPT_NO_AUTO_EXEMPT))
 				exempt_email_addr("SEND Auto-exempting", sender_info, toaddr);
 		}
-		status(STATUS_WFC);
 		/* Free up resources here */
 		if(mail!=NULL)
 			freemail(mail);
@@ -5955,7 +5938,6 @@ static void cleanup(int code)
 		lprintf(LOG_ERR,"0000 !WSACleanup ERROR %d",ERROR_VALUE);
 #endif
 	thread_down();
-	status("Down");
 	if(terminate_server || code) {
 		char str[1024];
 		sprintf(str,"%lu connections served", stats.connections_served);
@@ -6051,6 +6033,8 @@ void mail_server(void* arg)
 		return;
 	}
 
+	set_state(SERVER_INIT);
+
 	ZERO_VAR(js_server_props);
 	SAFEPRINTF3(js_server_props.version,"%s %s%c",server_name, VERSION, REVISION);
 	js_server_props.version_detail=mail_ver();
@@ -6088,8 +6072,6 @@ void mail_server(void* arg)
 		(void)protected_uint32_adjust(&thread_count,1);
 		thread_up(FALSE /* setuid */);
 
-		status("Initializing");
-
 		memset(&scfg, 0, sizeof(scfg));
 
 		lprintf(LOG_INFO,"%s Version %s%c%s"
@@ -6253,8 +6235,6 @@ void mail_server(void* arg)
 			_beginthread(sendmail_thread, 0, NULL);
 		}
 
-		status(STATUS_WFC);
-
 		/* Setup recycle/shutdown semaphore file lists */
 		shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","mail");
 		recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","mail");
@@ -6271,8 +6251,7 @@ void mail_server(void* arg)
 		savemsg_mutex_created = true;
 
 		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started(startup->cbdata);
+		set_state(SERVER_READY);
 
 		lprintf(LOG_INFO,"Mail Server thread started");
 
@@ -6391,6 +6370,8 @@ void mail_server(void* arg)
 			}
 		}
 
+		set_state(terminate_server ? SERVER_STOPPING : SERVER_RELOADING);
+
 		if(protected_uint32_value(active_clients)) {
 			lprintf(LOG_INFO,"Waiting for %d active clients to disconnect..."
 				, protected_uint32_value(active_clients));
@@ -6442,4 +6423,6 @@ void mail_server(void* arg)
 	} while(!terminate_server);
 
 	protected_uint32_destroy(thread_count);
+
+	set_state(SERVER_STOPPED);
 }
diff --git a/src/sbbs3/mailsrvr.h b/src/sbbs3/mailsrvr.h
index 8076ef2a61031fca6c65b8510cc9b66e6208d541..c78019b5cb57fa934e9cf8d90be49e85abb01538 100644
--- a/src/sbbs3/mailsrvr.h
+++ b/src/sbbs3/mailsrvr.h
@@ -63,8 +63,7 @@ typedef struct {
 	/* Callbacks (NULL if unused) */
 	int 	(*lputs)(void*, int level, const char* msg);
 	void	(*errormsg)(void*, int level, const char* msg);
-	void	(*status)(void*, const char*);
-    void	(*started)(void*);
+	void	(*set_state)(void*, enum server_state);
 	void	(*recycle)(void*);
     void	(*terminated)(void*, int code);
     void	(*clients)(void*, int active);
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 8a6b0c72ddd908f47241a14b424fc91b47850b43..258a1105a53ec87d8cee5ef6b5e8defc4462f1f8 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -157,11 +157,10 @@ extern "C" {
 
 static bbs_startup_t* startup=NULL;
 
-static const char* status(const char* str)
+static void set_state(enum server_state state)
 {
-	if(startup!=NULL && startup->status!=NULL)
-		startup->status(startup->cbdata,str);
-	return str;
+	if(startup != NULL && startup->set_state != NULL)
+		startup->set_state(startup->cbdata, state);
 }
 
 static void update_clients()
@@ -2777,8 +2776,6 @@ void event_thread(void* arg)
 				int userfile = openuserdat(&sbbs->cfg, /* for_modify: */FALSE);
 				for(i=1;i<=j;i++) {
 
-					SAFEPRINTF2(str,"%5u of %-5u",i,j);
-					//status(str);
 					sbbs->useron.number=i;
 					if(fgetuserdat(&sbbs->cfg,&sbbs->useron, userfile) != 0)
 						continue;
@@ -2824,7 +2821,6 @@ void event_thread(void* arg)
 				close(file);
 
 				remove(semfile);
-				//status(STATUS_WFC);
 			}
 			sbbs->useron.number = 0;
 		}
@@ -4448,8 +4444,6 @@ void node_thread(void* arg)
 		chsize(fileno(sbbs->logfile_fp), 0);
 	}
 
-	status(STATUS_WFC);
-
 	sbbs->getnodedat(sbbs->cfg.node_num,&node,1);
 	if(node.misc&NODE_DOWN)
 		node.status=NODE_OFFLINE;
@@ -4576,8 +4570,6 @@ void sbbs_t::daily_maint(void)
 	lastusernum=lastuser(&cfg);
 	int userfile=openuserdat(&cfg, /* for_modify: */FALSE);
 	for(usernum=1;usernum<=lastusernum;usernum++) {
-		SAFEPRINTF2(str,"%5u of %-5u",usernum,lastusernum);
-		status(str);
 		user.number = usernum;
 		if((i=fgetuserdat(&cfg, &user, userfile)) != 0) {
 			SAFEPRINTF(str,"user record %u",usernum);
@@ -4691,7 +4683,6 @@ void sbbs_t::daily_maint(void)
 		online = FALSE;
 		lprintf(result ? LOG_ERR : LOG_INFO, "Daily event: '%s' returned %d", cmd, result);
 	}
-	status(STATUS_WFC);
 	lputs(LOG_INFO, "DAILY: System maintenance ended");
 	sys_status&=~SS_DAILY;
 }
@@ -4773,7 +4764,6 @@ static void cleanup(int code)
 	protected_uint32_destroy(node_threads_running);
 	protected_uint32_destroy(ssh_sessions);
 
-	status("Down");
 	thread_down();
 	if(terminate_server || code)
 		lprintf(LOG_INFO,"Terminal Server thread terminated (%lu clients served)", served);
@@ -4828,6 +4818,8 @@ void bbs_thread(void* arg)
 		return;
 	}
 
+	set_state(SERVER_INIT);
+
 #ifdef _THREAD_SUID_BROKEN
 	if(thread_suid_broken)
 		startup->seteuid(TRUE);
@@ -4867,8 +4859,6 @@ void bbs_thread(void* arg)
 	if(startup->seteuid!=NULL)
 		startup->seteuid(TRUE);
 
-	status("Initializing");
-
 	memset(text, 0, sizeof(text));
     memset(&scfg, 0, sizeof(scfg));
 
@@ -5173,8 +5163,6 @@ NO_SSH:
 		sbbs->putnodedat(i,&node);
 	}
 
-	status(STATUS_WFC);
-
 	/* Setup recycle/shutdown semaphore file lists */
 	shutdown_semfiles = semfile_list_init(scfg.ctrl_dir,"shutdown", "term");
 	recycle_semfiles = semfile_list_init(scfg.ctrl_dir,"recycle", "term");
@@ -5212,8 +5200,7 @@ NO_SSH:
 #endif // __unix__ (unix-domain spy sockets)
 
 	/* signal caller that we've started up successfully */
-	if(startup->started!=NULL)
-		startup->started(startup->cbdata);
+	set_state(SERVER_READY);
 
 	lprintf(LOG_INFO,"Terminal Server thread started for nodes %d through %d", first_node, last_node);
 
@@ -5792,6 +5779,8 @@ NO_SSH:
 		served++;
 	}
 
+	set_state(terminate_server ? SERVER_STOPPING : SERVER_RELOADING);
+
     // Close all open sockets
     for(i=0;i<MAX_NODES;i++)  {
     	if(node_socket[i]!=INVALID_SOCKET) {
@@ -5907,4 +5896,5 @@ NO_SSH:
 
 	} while(!terminate_server);
 
+	set_state(SERVER_STOPPED);
 }
diff --git a/src/sbbs3/sbbscon.c b/src/sbbs3/sbbscon.c
index 308fb6cfdc94f5d1257c1eb406cb61187197647e..b5dbc1ab97c7cda4009c4ba3521d18aae6d37573 100644
--- a/src/sbbs3/sbbscon.c
+++ b/src/sbbs3/sbbscon.c
@@ -32,6 +32,9 @@
 #ifdef __QNX__
 #include <locale.h>
 #endif
+#ifdef USE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
 
 /* Synchronet-specific headers */
 #undef SBBS	/* this shouldn't be defined unless building sbbs.dll/libsbbs.so */
@@ -47,7 +50,6 @@
 #include "threadwrap.h"	/* pthread_mutex_t */
 
 #ifdef __unix__
-#include "sbbs_status.h"
 
 #ifdef USE_LINUX_CAPS
 #include <sys/capability.h>
@@ -67,30 +69,16 @@
 /* Global variables */
 BOOL				terminated=FALSE;
 
+enum server_state	server_state[SERVER_COUNT];
 BOOL				run_bbs=FALSE;
-BOOL				bbs_running=FALSE;
-BOOL				bbs_stopped=FALSE;
-BOOL				has_bbs=FALSE;
 bbs_startup_t		bbs_startup;
 BOOL				run_ftp=FALSE;
-BOOL				ftp_running=FALSE;
-BOOL				ftp_stopped=FALSE;
-BOOL				has_ftp=FALSE;
 ftp_startup_t		ftp_startup;
 BOOL				run_mail=FALSE;
-BOOL				mail_running=FALSE;
-BOOL				mail_stopped=FALSE;
-BOOL				has_mail=FALSE;
 mail_startup_t		mail_startup;
 BOOL				run_services=FALSE;
-BOOL				services_running=FALSE;
-BOOL				services_stopped=FALSE;
-BOOL				has_services=FALSE;
 services_startup_t	services_startup;
 BOOL				run_web=FALSE;
-BOOL				web_running=FALSE;
-BOOL				web_stopped=FALSE;
-BOOL				has_web=FALSE;
 web_startup_t		web_startup;
 ulong				thread_count=1;
 ulong				socket_count=0;
@@ -102,10 +90,7 @@ char				ini_file[MAX_PATH+1];
 link_list_t			login_attempt_list;
 link_list_t			client_list;
 
-BOOL				status_running=FALSE;
 #ifdef __unix__
-sbbs_status_startup_t	status_startup;
-BOOL				status_stopped=FALSE;
 char				new_uid_name[32];
 char				new_gid_name[32];
 uid_t				new_uid;
@@ -215,6 +200,44 @@ static const char* web_usage  = "Web server settings:\n"
 							"\tw-         disable Web server\n"
 							;
 
+static bool server_running(enum server_type type)
+{
+	return server_state[type] != SERVER_STOPPED;
+}
+
+static bool any_server_running()
+{
+	for(int i = 0; i < SERVER_COUNT; i++)
+		if(server_state[i] != SERVER_STOPPED)
+			return true;
+	return false;
+}
+
+static bool any_server_with_state(enum server_state state)
+{
+	for(int i = 0; i < SERVER_COUNT; i++)
+		if(server_state[i] == state)
+			return true;
+	return false;
+}
+
+#ifdef USE_SYSTEMD
+static void notify_systemd(const char* new_status)
+{
+	static char status[1024];
+	if(new_status != NULL)
+		SAFECOPY(status, new_status);
+	char* ready = "";
+	if(any_server_with_state(SERVER_RELOADING))
+		ready = "RELOADING=1";
+	else if(any_server_with_state(SERVER_STOPPING))
+		ready = "STOPPING=1";
+	else if(any_server_running())
+		ready = "READY=1";
+	sd_notifyf(/* unset_environment: */0, "%s\nSTATUS=%s", ready, status);
+}
+#endif
+
 static int lputs(int level, char *str)
 {
 	static pthread_mutex_t mutex;
@@ -229,6 +252,9 @@ static int lputs(int level, char *str)
 				syslog(level|LOG_AUTH,"%s",str);
 			else
 				syslog(level,"%s",str);
+#ifdef USE_SYSTEMD
+			notify_systemd(str);
+#endif
 		}
 		return(0);
 	}
@@ -260,20 +286,6 @@ static int lputs(int level, char *str)
 
 static void errormsg(void *cbdata, int level, const char *msg)
 {
-#ifdef __unix__
-	if(cbdata==&bbs_startup)
-		status_errormsg(SERVICE_TERM, level, msg);
-	else if(cbdata==&ftp_startup)
-		status_errormsg(SERVICE_FTP, level, msg);
-	else if(cbdata==&web_startup)
-		status_errormsg(SERVICE_WEB, level, msg);
-	else if(cbdata==&mail_startup)
-		status_errormsg(SERVICE_MAIL, level, msg);
-	else if(cbdata==&services_startup)
-		status_errormsg(SERVICE_SERVICES, level, msg);
-	else if(cbdata==&status_startup)
-		status_errormsg(SERVICE_STATUS, level, msg);
-#endif
 	error_count++;
 }
 
@@ -553,26 +565,28 @@ static BOOL winsock_cleanup(void)
 
 #endif
 
+static void set_state(void* server, enum server_state state)
+{
+	server_state[(enum server_type)server] = state;
+#ifdef USE_SYSTEMD
+	notify_systemd(NULL);
+#endif
+
+#ifdef _THREAD_SUID_BROKEN
+	if(state == SERVER_READY) {
+        if(thread_suid_broken) {
+            do_seteuid(FALSE);
+            do_setuid(FALSE);
+        }
+	}
+#endif
+}
+
 static void thread_up(void* p, BOOL up, BOOL setuid)
 {
    	static pthread_mutex_t mutex;
 	static BOOL mutex_initialized;
 
-#ifdef __unix__
-	if(p==&bbs_startup)
-		status_thread_up(SERVICE_TERM, up, setuid);
-	else if(p==&ftp_startup)
-		status_thread_up(SERVICE_FTP, up, setuid);
-	else if(p==&web_startup)
-		status_thread_up(SERVICE_WEB, up, setuid);
-	else if(p==&mail_startup)
-		status_thread_up(SERVICE_MAIL, up, setuid);
-	else if(p==&services_startup)
-		status_thread_up(SERVICE_SERVICES, up, setuid);
-	else if(p==&status_startup)
-		status_thread_up(SERVICE_STATUS, up, setuid);
-#endif
-
 #ifdef _THREAD_SUID_BROKEN
 	if(thread_suid_broken && up && setuid) {
 		do_seteuid(FALSE);
@@ -605,21 +619,6 @@ static void socket_open(void* p, BOOL open)
 		mutex_initialized=TRUE;
 	}
 
-#ifdef __unix__
-	if(p==&bbs_startup)
-		status_socket_open(SERVICE_TERM, open);
-	else if(p==&ftp_startup)
-		status_socket_open(SERVICE_FTP, open);
-	else if(p==&web_startup)
-		status_socket_open(SERVICE_WEB, open);
-	else if(p==&mail_startup)
-		status_socket_open(SERVICE_MAIL, open);
-	else if(p==&services_startup)
-		status_socket_open(SERVICE_SERVICES, open);
-	else if(p==&status_startup)
-		status_socket_open(SERVICE_STATUS, open);
-#endif
-
 	pthread_mutex_lock(&mutex);
 	if(open)
 	    socket_count++;
@@ -631,21 +630,6 @@ static void socket_open(void* p, BOOL open)
 
 static void client_on(void* p, BOOL on, int sock, client_t* client, BOOL update)
 {
-#ifdef __unix__
-	if(p==&bbs_startup)
-		status_client_on(SERVICE_TERM, on, sock, client, update);
-	else if(p==&ftp_startup)
-		status_client_on(SERVICE_FTP, on, sock, client, update);
-	else if(p==&web_startup)
-		status_client_on(SERVICE_WEB, on, sock, client, update);
-	else if(p==&mail_startup)
-		status_client_on(SERVICE_MAIL, on, sock, client, update);
-	else if(p==&services_startup)
-		status_client_on(SERVICE_SERVICES, on, sock, client, update);
-	else if(p==&status_startup)
-		status_client_on(SERVICE_STATUS, on, sock, client, update);
-#endif
-
 	if(on) {
 		if(update) {
 			list_node_t*	node;
@@ -678,7 +662,6 @@ static int bbs_lputs(void* p, int level, const char *str)
 		return(0);
 
 #ifdef __unix__
-	status_lputs(SERVICE_TERM, level, str);
 	if (is_daemon || syslog_always)  {
 		if(str==NULL)
 			return(0);
@@ -706,91 +689,6 @@ static int bbs_lputs(void* p, int level, const char *str)
     return(strlen(logline)+1);
 }
 
-static void bbs_started(void* p)
-{
-#ifdef __unix__
-	status_started(SERVICE_TERM);
-#endif
-	bbs_running=TRUE;
-	bbs_stopped=FALSE;
-#ifdef _THREAD_SUID_BROKEN
-        if(thread_suid_broken) {
-            do_seteuid(FALSE);
-            do_setuid(FALSE);
-        }
-#endif
-}
-
-static void bbs_terminated(void* p, int code)
-{
-#ifdef __unix__
-	status_terminated(SERVICE_TERM, code);
-#endif
-	bbs_running=FALSE;
-	bbs_stopped=TRUE;
-}
-
-/****************************************************************************/
-/* Status local/log print routine										*/
-/****************************************************************************/
-#ifdef __unix__
-static int stat_lputs(void* p, int level, const char *str)
-{
-	char		logline[512];
-	char		tstr[64];
-	time_t		t;
-	struct tm	tm;
-
-	if(level > bbs_startup.log_level)
-		return(0);
-
-	status_lputs(SERVICE_STATUS, level, str);
-	if (is_daemon || syslog_always)  {
-		if(str==NULL)
-			return(0);
-		if (std_facilities)
-			syslog(level|LOG_AUTH,"%s",str);
-		else
-			syslog(level,"stat %s",str);
-		if(is_daemon)
-			return(strlen(str));
-	}
-
-	t=time(NULL);
-	if(localtime_r(&t,&tm)==NULL)
-		tstr[0]=0;
-	else
-		sprintf(tstr,"%d/%d %02d:%02d:%02d "
-			,tm.tm_mon+1,tm.tm_mday
-			,tm.tm_hour,tm.tm_min,tm.tm_sec);
-
-	sprintf(logline,"%sstat %.*s",tstr,(int)sizeof(logline)-70,str);
-	truncsp(logline);
-	lputs(level,logline);
-
-	return(strlen(logline)+1);
-}
-
-static void stat_started(void* p)
-{
-	status_started(SERVICE_STATUS);
-	status_running=TRUE;
-	status_stopped=FALSE;
-#ifdef _THREAD_SUID_BROKEN
-        if(thread_suid_broken) {
-            do_seteuid(FALSE);
-            do_setuid(FALSE);
-        }
-#endif
-}
-
-static void stat_terminated(void* p, int code)
-{
-	status_terminated(SERVICE_STATUS, code);
-	status_running=FALSE;
-	status_stopped=TRUE;
-}
-#endif
 
 /****************************************************************************/
 /* FTP local/log print routine												*/
@@ -806,7 +704,6 @@ static int ftp_lputs(void* p, int level, const char *str)
 		return(0);
 
 #ifdef __unix__
-	status_lputs(SERVICE_FTP, level, str);
 	if (is_daemon || syslog_always)  {
 		if(str==NULL)
 			return(0);
@@ -838,30 +735,6 @@ static int ftp_lputs(void* p, int level, const char *str)
     return(strlen(logline)+1);
 }
 
-static void ftp_started(void* p)
-{
-#ifdef __unix__
-	status_started(SERVICE_FTP);
-#endif
-	ftp_running=TRUE;
-	ftp_stopped=FALSE;
-#ifdef _THREAD_SUID_BROKEN
-	if(thread_suid_broken) {
-		do_seteuid(FALSE);
-		do_setuid(FALSE);
-	}
-#endif
-}
-
-static void ftp_terminated(void* p, int code)
-{
-#ifdef __unix__
-	status_terminated(SERVICE_FTP, code);
-#endif
-	ftp_running=FALSE;
-	ftp_stopped=TRUE;
-}
-
 /****************************************************************************/
 /* Mail Server local/log print routine										*/
 /****************************************************************************/
@@ -876,7 +749,6 @@ static int mail_lputs(void* p, int level, const char *str)
 		return(0);
 
 #ifdef __unix__
-	status_lputs(SERVICE_MAIL, level, str);
 	if (is_daemon || syslog_always)  {
 		if(str==NULL)
 			return(0);
@@ -904,30 +776,6 @@ static int mail_lputs(void* p, int level, const char *str)
     return(strlen(logline)+1);
 }
 
-static void mail_started(void* p)
-{
-#ifdef __unix__
-	status_started(SERVICE_MAIL);
-#endif
-	mail_running=TRUE;
-	mail_stopped=FALSE;
-#ifdef _THREAD_SUID_BROKEN
-	if(thread_suid_broken) {
-		do_seteuid(FALSE);
-		do_setuid(FALSE);
-	}
-#endif
-}
-
-static void mail_terminated(void* p, int code)
-{
-#ifdef __unix__
-	status_terminated(SERVICE_MAIL, code);
-#endif
-	mail_running=FALSE;
-	mail_stopped=TRUE;
-}
-
 /****************************************************************************/
 /* Services local/log print routine											*/
 /****************************************************************************/
@@ -942,7 +790,6 @@ static int services_lputs(void* p, int level, const char *str)
 		return(0);
 
 #ifdef __unix__
-	status_lputs(SERVICE_SERVICES, level, str);
 	if (is_daemon || syslog_always)  {
 		if(str==NULL)
 			return(0);
@@ -970,30 +817,6 @@ static int services_lputs(void* p, int level, const char *str)
     return(strlen(logline)+1);
 }
 
-static void services_started(void* p)
-{
-#ifdef __unix__
-	status_started(SERVICE_SERVICES);
-#endif
-	services_running=TRUE;
-	services_stopped=FALSE;
-	#ifdef _THREAD_SUID_BROKEN
-		if(thread_suid_broken) {
-	    	do_seteuid(FALSE);
-	    	do_setuid(FALSE);
-		}
-	#endif
-}
-
-static void services_terminated(void* p, int code)
-{
-#ifdef __unix__
-	status_terminated(SERVICE_SERVICES, code);
-#endif
-	services_running=FALSE;
-	services_stopped=TRUE;
-}
-
 /****************************************************************************/
 /* Event thread local/log print routine										*/
 /****************************************************************************/
@@ -1008,7 +831,6 @@ static int event_lputs(void* p, int level, const char *str)
 		return(0);
 
 #ifdef __unix__
-	status_lputs(SERVICE_EVENT, level, str);
 	if (is_daemon || syslog_always)  {
 		if(str==NULL)
 			return(0);
@@ -1050,7 +872,6 @@ static int web_lputs(void* p, int level, const char *str)
 		return(0);
 
 #ifdef __unix__
-	status_lputs(SERVICE_WEB, level, str);
 	if (is_daemon || syslog_always)  {
 		if(str==NULL)
 			return(0);
@@ -1078,67 +899,34 @@ static int web_lputs(void* p, int level, const char *str)
     return(strlen(logline)+1);
 }
 
-static void web_started(void* p)
-{
-#ifdef __unix__
-	status_started(SERVICE_WEB);
-#endif
-	web_running=TRUE;
-	web_stopped=FALSE;
-#ifdef _THREAD_SUID_BROKEN
-	if(thread_suid_broken) {
-		do_seteuid(FALSE);
-		do_setuid(FALSE);
-	}
-#endif
-}
-
-static void web_terminated(void* p, int code)
-{
-#ifdef __unix__
-	status_terminated(SERVICE_WEB, code);
-#endif
-	web_running=FALSE;
-	web_stopped=TRUE;
-}
-
 static void terminate(void)
 {
 	ulong count=0;
 
 	prompt = "[Threads: %d  Sockets: %d  Clients: %d  Served: %lu  Errors: %lu] Terminating... ";
-#ifdef __unix__
-	status_thread_terminate();
-#endif
-	if(bbs_running)
+	if(server_running(SERVER_TERM))
 		bbs_terminate();
-	if(ftp_running)
+	if(server_running(SERVER_FTP))
 		ftp_terminate();
-#ifndef NO_WEB_SERVER
-	if(web_running)
+	if(server_running(SERVER_WEB))
 		web_terminate();
-#endif
-	if(mail_running)
+	if(server_running(SERVER_MAIL))
 		mail_terminate();
-#ifndef NO_SERVICES
-	if(services_running)
+	if(server_running(SERVER_SERVICES))
 		services_terminate();
-#endif
 
-	while(bbs_running || ftp_running || web_running || mail_running || services_running || status_running)  {
+	while(any_server_running()) {
 		if(count && (count%10)==0) {
-			if(bbs_running)
+			if(server_running(SERVER_TERM))
 				lputs(LOG_INFO,"Terminal Server thread still running");
-			if(ftp_running)
+			if(server_running(SERVER_FTP))
 				lprintf(LOG_INFO,"FTP Server thread still running (inactivity timeout: %u seconds)", ftp_startup.max_inactivity);
-			if(web_running)
+			if(server_running(SERVER_WEB))
 				lprintf(LOG_INFO,"Web Server thread still running (inactivity timeout: %u seconds)", web_startup.max_inactivity);
-			if(mail_running)
+			if(server_running(SERVER_MAIL))
 				lprintf(LOG_INFO,"Mail Server thread still running (inactivity timeout: %u seconds)", mail_startup.max_inactivity);
-			if(services_running)
+			if(server_running(SERVER_SERVICES))
 				lputs(LOG_INFO,"Services thread still running");
-			if (status_running)
-				lputs(LOG_INFO,"Status thread still running");
 		}
 		count++;
 		SLEEP(1000);
@@ -1201,35 +989,24 @@ void recycle(void* cbdata)
 	mail_startup_t* mail=NULL;
 	services_startup_t* services=NULL;
 
-	if(cbdata==&bbs_startup) {
-#ifdef __unix__
-		status_recycle(SERVICE_TERM);
-#endif
-		bbs=cbdata;
-	}
-	else if(cbdata==&ftp_startup) {
-#ifdef __unix__
-		status_recycle(SERVICE_FTP);
-#endif
-		ftp=cbdata;
-	}
-	else if(cbdata==&web_startup) {
-#ifdef __unix__
-		status_recycle(SERVICE_WEB);
-#endif
-		web=cbdata;
-	}
-	else if(cbdata==&mail_startup) {
-#ifdef __unix__
-		status_recycle(SERVICE_MAIL);
-#endif
-		mail=cbdata;
-	}
-	else if(cbdata==&services_startup) {
-#ifdef __unix__
-		status_recycle(SERVICE_SERVICES);
-#endif
-		services=cbdata;
+	switch((enum server_type)cbdata) {
+		case SERVER_TERM:
+			bbs = &bbs_startup;
+			break;
+		case SERVER_MAIL:
+			mail = &mail_startup;
+			break;
+		case SERVER_FTP:
+			ftp = &ftp_startup;
+			break;
+		case SERVER_WEB:
+			web = &web_startup;
+			break;
+		case SERVER_SERVICES:
+			services  = &services_startup;
+			break;
+		default:
+			return;
 	}
 
 	read_startup_ini(/* recycle? */TRUE,bbs,ftp,web,mail,services);
@@ -1350,16 +1127,11 @@ static void handle_sigs(void)
 static void show_usage(char *cmd)
 {
 	printf(usage,cmd);
-	if(has_bbs)
-		puts(telnet_usage);
-	if(has_ftp)
-		puts(ftp_usage);
-	if(has_mail)
-		puts(mail_usage);
-	if(has_services)
-		puts(services_usage);
-	if(has_web)
-		puts(web_usage);
+	puts(telnet_usage);
+	puts(ftp_usage);
+	puts(mail_usage);
+	puts(services_usage);
+	puts(web_usage);
 }
 
 /****************************************************************************/
@@ -1423,68 +1195,38 @@ int main(int argc, char** argv)
 	/* Initialize BBS startup structure */
     memset(&bbs_startup,0,sizeof(bbs_startup));
     bbs_startup.size=sizeof(bbs_startup);
-	bbs_startup.cbdata=&bbs_startup;
+	bbs_startup.cbdata = (void*)SERVER_TERM;
 	bbs_startup.log_level = LOG_DEBUG;
 	bbs_startup.lputs=bbs_lputs;
 	bbs_startup.event_lputs=event_lputs;
 	bbs_startup.errormsg=errormsg;
-    bbs_startup.started=bbs_started;
+    bbs_startup.set_state = set_state;
 	bbs_startup.recycle=recycle;
-    bbs_startup.terminated=bbs_terminated;
     bbs_startup.thread_up=thread_up;
     bbs_startup.socket_open=socket_open;
     bbs_startup.client_on=client_on;
 #ifdef __unix__
 	bbs_startup.seteuid=do_seteuid;
 	bbs_startup.setuid=do_setuid;
-    bbs_startup.status=status_term_status;
-    bbs_startup.clients=status_term_clients;
 #endif
 	bbs_startup.login_attempt_list=&login_attempt_list;
     SAFECOPY(bbs_startup.ctrl_dir,ctrl_dir);
 
-#ifdef __unix__
-
-#endif
-
-#ifdef __unix__
-	/* Initialize status startup structure */
-    memset(&status_startup,0,sizeof(status_startup));
-    status_startup.size=sizeof(status_startup);
-	status_startup.cbdata=&status_startup;
-	status_startup.log_level = LOG_DEBUG;
-	status_startup.lputs=stat_lputs;
-	status_startup.errormsg=errormsg;
-    status_startup.started=stat_started;
-    status_startup.terminated=stat_terminated;
-	status_startup.thread_up=thread_up;
-    status_startup.socket_open=socket_open;
-    status_startup.client_on=client_on;
-	status_startup.seteuid=do_seteuid;
-	status_startup.setuid=do_setuid;
-	status_startup.clients=status_status_clients;
-	status_startup.status=status_status_status;	// Heh.
-    SAFECOPY(status_startup.ctrl_dir,ctrl_dir);
-#endif
-
 	/* Initialize FTP startup structure */
     memset(&ftp_startup,0,sizeof(ftp_startup));
     ftp_startup.size=sizeof(ftp_startup);
-	ftp_startup.cbdata=&ftp_startup;
+	ftp_startup.cbdata = (void*)SERVER_FTP;
 	ftp_startup.log_level = LOG_DEBUG;
 	ftp_startup.lputs=ftp_lputs;
 	ftp_startup.errormsg=errormsg;
-    ftp_startup.started=ftp_started;
+    ftp_startup.set_state = set_state;
 	ftp_startup.recycle=recycle;
-    ftp_startup.terminated=ftp_terminated;
 	ftp_startup.thread_up=thread_up;
     ftp_startup.socket_open=socket_open;
     ftp_startup.client_on=client_on;
 #ifdef __unix__
 	ftp_startup.seteuid=do_seteuid;
 	ftp_startup.setuid=do_setuid;
-	ftp_startup.clients=status_ftp_clients;
-	ftp_startup.status=status_ftp_status;
 #endif
 	ftp_startup.login_attempt_list=&login_attempt_list;
     SAFECOPY(ftp_startup.index_file_name,"00index");
@@ -1493,21 +1235,18 @@ int main(int argc, char** argv)
 	/* Initialize Web Server startup structure */
     memset(&web_startup,0,sizeof(web_startup));
     web_startup.size=sizeof(web_startup);
-	web_startup.cbdata=&web_startup;
+	web_startup.cbdata = (void*)SERVER_WEB;
 	web_startup.log_level = LOG_DEBUG;
 	web_startup.lputs=web_lputs;
 	web_startup.errormsg=errormsg;
-    web_startup.started=web_started;
+    web_startup.set_state = set_state;
 	web_startup.recycle=recycle;
-    web_startup.terminated=web_terminated;
 	web_startup.thread_up=thread_up;
     web_startup.socket_open=socket_open;
 	web_startup.client_on=client_on;
 #ifdef __unix__
 	web_startup.seteuid=do_seteuid;
 	web_startup.setuid=do_setuid;
-	web_startup.clients=status_web_clients;
-	web_startup.status=status_web_status;
 #endif
 	web_startup.login_attempt_list=&login_attempt_list;
     SAFECOPY(web_startup.ctrl_dir,ctrl_dir);
@@ -1515,21 +1254,18 @@ int main(int argc, char** argv)
 	/* Initialize Mail Server startup structure */
     memset(&mail_startup,0,sizeof(mail_startup));
     mail_startup.size=sizeof(mail_startup);
-	mail_startup.cbdata=&mail_startup;
+	mail_startup.cbdata = (void*)SERVER_MAIL;
 	mail_startup.log_level = LOG_DEBUG;
 	mail_startup.lputs=mail_lputs;
 	mail_startup.errormsg=errormsg;
-    mail_startup.started=mail_started;
+    mail_startup.set_state = set_state;
 	mail_startup.recycle=recycle;
-    mail_startup.terminated=mail_terminated;
 	mail_startup.thread_up=thread_up;
     mail_startup.socket_open=socket_open;
     mail_startup.client_on=client_on;
 #ifdef __unix__
 	mail_startup.seteuid=do_seteuid;
 	mail_startup.setuid=do_setuid;
-	mail_startup.clients=status_mail_clients;
-	mail_startup.status=status_mail_status;
 #endif
 	mail_startup.login_attempt_list=&login_attempt_list;
     SAFECOPY(mail_startup.ctrl_dir,ctrl_dir);
@@ -1537,21 +1273,18 @@ int main(int argc, char** argv)
 	/* Initialize Services startup structure */
     memset(&services_startup,0,sizeof(services_startup));
     services_startup.size=sizeof(services_startup);
-	services_startup.cbdata=&services_startup;
+	services_startup.cbdata = (void*)SERVER_SERVICES;
 	services_startup.log_level = LOG_DEBUG;
 	services_startup.lputs=services_lputs;
 	services_startup.errormsg=errormsg;
-    services_startup.started=services_started;
+    services_startup.set_state = set_state;
 	services_startup.recycle=recycle;
-    services_startup.terminated=services_terminated;
 	services_startup.thread_up=thread_up;
     services_startup.socket_open=socket_open;
     services_startup.client_on=client_on;
 #ifdef __unix__
 	services_startup.seteuid=do_seteuid;
 	services_startup.setuid=do_setuid;
-	services_startup.clients=status_services_clients;
-	services_startup.status=status_services_status;
 #endif
 	services_startup.login_attempt_list=&login_attempt_list;
     SAFECOPY(services_startup.ctrl_dir,ctrl_dir);
@@ -1590,27 +1323,8 @@ int main(int argc, char** argv)
 		}
 	}
 
-#ifdef __unix__
-	SAFECOPY(status_startup.sock_fname, ini_file);
-	{
-		p = getfname(status_startup.sock_fname);
-		if (p && *p) {
-			char *ext = getfext(p);
-			if (ext == NULL)
-				ext = strchr(p, 0);
-			sprintf(ext, ".sock");
-			if (strncmp(p, "sbbs.", 5)==0)
-				SAFECOPY(str, p+5);
-			else
-				SAFECOPY(str, p);
-			sprintf(p, "status.%s", str);
-		}
-	}
-#endif
-
 	read_startup_ini(/* recycle? */FALSE
 		,&bbs_startup, &ftp_startup, &web_startup, &mail_startup, &services_startup);
-	has_web=has_bbs=has_ftp=has_mail=has_services=TRUE;
 
 	/* Post-INI command-line switches */
 	for(i=1;i<argc;i++) {
@@ -1817,18 +1531,12 @@ int main(int argc, char** argv)
 							SAFECOPY(mail_startup.host_name,arg);
 							SAFECOPY(services_startup.host_name,arg);
 							SAFECOPY(web_startup.host_name,arg);
-#ifdef __unix__
-							SAFECOPY(status_startup.host_name,arg);
-#endif
 						} else {
 							SAFECOPY(bbs_startup.host_name,host_name);
 							SAFECOPY(ftp_startup.host_name,host_name);
 							SAFECOPY(mail_startup.host_name,host_name);
 							SAFECOPY(services_startup.host_name,host_name);
 							SAFECOPY(web_startup.host_name,host_name);
-#ifdef __unix__
-							SAFECOPY(status_startup.host_name,host_name);
-#endif
 						}
 						printf("Setting hostname: %s\n",bbs_startup.host_name);
 						break;
@@ -2093,7 +1801,6 @@ int main(int argc, char** argv)
 #endif /* !defined(DONT_BLAME_SYNCHRONET) */
 		}
     } /* end if(!capabilities_set) */
-	_beginthread(status_thread, 0, &status_startup);
 #endif /* defined(__unix__) */
 
 	if(run_bbs)
@@ -2102,18 +1809,10 @@ int main(int argc, char** argv)
 		_beginthread((void(*)(void*))ftp_server,0,&ftp_startup);
 	if(run_mail)
 		_beginthread((void(*)(void*))mail_server,0,&mail_startup);
-#ifdef NO_SERVICES
-	run_services=FALSE;
-#else
 	if(run_services)
 		_beginthread((void(*)(void*))services_thread,0,&services_startup);
-#endif
-#ifdef NO_WEB_SERVER
-	run_web=FALSE;
-#else
 	if(run_web)
 		_beginthread((void(*)(void*))web_server,0,&web_startup);
-#endif
 
 #ifdef __unix__
 	uid_t uid = getuid();
@@ -2127,21 +1826,17 @@ int main(int argc, char** argv)
     else
     {
     	lputs(LOG_INFO,"Waiting for child threads to bind ports...");
-	   	while((run_bbs && !(bbs_running || bbs_stopped))
-			|| (run_ftp && !(ftp_running || ftp_stopped))
-			|| (run_web && !(web_running || web_stopped))
-			|| (run_mail && !(mail_running || mail_stopped))
-			|| (run_services && !(services_running || services_stopped)))  {
+		while(any_server_running()) {
 	    	mswait(1000);
-		    if(run_bbs && !(bbs_running || bbs_stopped))
+		    if(server_running(SERVER_TERM))
 			    lputs(LOG_INFO,"Waiting for BBS thread");
-		    if(run_web && !(web_running || web_stopped))
+		    if(server_running(SERVER_WEB))
 			    lputs(LOG_INFO,"Waiting for Web thread");
-		    if(run_ftp && !(ftp_running || ftp_stopped))
+		    if(server_running(SERVER_FTP))
 			    lputs(LOG_INFO,"Waiting for FTP thread");
-		    if(run_mail && !(mail_running || mail_stopped))
+		    if(server_running(SERVER_MAIL))
 			    lputs(LOG_INFO,"Waiting for Mail thread");
-		    if(run_services && !(services_running || services_stopped))
+		    if(server_running(SERVER_SERVICES))
 			    lputs(LOG_INFO,"Waiting for Services thread");
 	    }
 
diff --git a/src/sbbs3/services.c b/src/sbbs3/services.c
index 756d95d9e2619d3ae6357d738b3328afe766be69..93630c52acf849bfdd268b39e7fd67c5b75c823e 100644
--- a/src/sbbs3/services.c
+++ b/src/sbbs3/services.c
@@ -173,6 +173,12 @@ static char* server_host_name(void)
 	return startup->host_name[0] ? startup->host_name : scfg.sys_inetaddr;
 }
 
+static void set_state(enum server_state state)
+{
+	if(startup != NULL && startup->set_state != NULL)
+		startup->set_state(startup->cbdata, state);
+}
+
 static ulong active_clients(void)
 {
 	ulong i;
@@ -261,12 +267,6 @@ static int close_socket(SOCKET sock)
 	return(result);
 }
 
-static void status(char* str)
-{
-	if(startup!=NULL && startup->status!=NULL)
-	    startup->status(startup->cbdata,str);
-}
-
 /* Global JavaScript Methods */
 
 static JSBool
@@ -1711,7 +1711,6 @@ static void cleanup(int code)
 	thread_down();
 	if(terminated || code)
 		lprintf(LOG_INFO,"#### Services thread terminated (%lu clients served)",served);
-	status("Down");
 	if(startup!=NULL && startup->terminated!=NULL)
 		startup->terminated(startup->cbdata,code);
 }
@@ -1854,6 +1853,7 @@ void services_thread(void* arg)
 		fprintf(stderr, "Invalid startup structure!\n");
 		return;
 	}
+	set_state(SERVER_INIT);
 
 #ifdef _THREAD_SUID_BROKEN
 	if(thread_suid_broken)
@@ -1874,8 +1874,6 @@ void services_thread(void* arg)
 
 		thread_up(FALSE /* setuid */);
 
-		status("Initializing");
-
 		memset(&scfg, 0, sizeof(scfg));
 
 		lprintf(LOG_INFO,"Synchronet Services Version %s%c%s"
@@ -2012,8 +2010,6 @@ void services_thread(void* arg)
 			}
 		}
 
-		status("Listening");
-
 		/* Setup recycle/shutdown semaphore file lists */
 		shutdown_semfiles=semfile_list_init(scfg.ctrl_dir,"shutdown","services");
 		recycle_semfiles=semfile_list_init(scfg.ctrl_dir,"recycle","services");
@@ -2029,8 +2025,7 @@ void services_thread(void* arg)
 		terminated=FALSE;
 
 		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started(startup->cbdata);
+		set_state(SERVER_READY);
 
 		if (need_cert) {
 			if (get_ssl_cert(&scfg, &ssl_estr, &level) == -1) {
@@ -2345,6 +2340,8 @@ void services_thread(void* arg)
 #endif
 			}
 		}
+		set_state(terminated ? SERVER_STOPPING : SERVER_RELOADING);
+
 #ifdef PREFER_POLL
 		FREE_AND_NULL(fds);
 #endif
@@ -2396,4 +2393,6 @@ void services_thread(void* arg)
 		}
 
 	} while(!terminated);
+
+	set_state(SERVER_STOPPED);
 }
diff --git a/src/sbbs3/services.h b/src/sbbs3/services.h
index 62bd3680874c7bf5e473e8bb4ba41a48c8e4e7e6..eb4100e7626408b814cdb13092139cb1b7ed96ce 100644
--- a/src/sbbs3/services.h
+++ b/src/sbbs3/services.h
@@ -36,8 +36,7 @@ typedef struct {
 	/* Callbacks (NULL if unused) */
 	int 	(*lputs)(void*, int level, const char*);		/* Log - put string */
 	void	(*errormsg)(void*, int level, const char* msg);
-	void	(*status)(void*, const char*);
-    void	(*started)(void*);
+	void	(*set_state)(void*, enum server_state);
 	void	(*recycle)(void*);
     void	(*terminated)(void*, int code);
     void	(*clients)(void*, int active);
diff --git a/src/sbbs3/startup.h b/src/sbbs3/startup.h
index 65ec7fb5ad9dd4aa5009301ffdd387dbfad9ec24..8b87167c176f96ea9f6d018f75a86cc0f35adb4d 100644
--- a/src/sbbs3/startup.h
+++ b/src/sbbs3/startup.h
@@ -79,6 +79,24 @@ typedef struct {
 
 } global_startup_t;
 
+enum server_type {
+	SERVER_TERM,
+	SERVER_MAIL,
+	SERVER_FTP,
+	SERVER_WEB,
+	SERVER_SERVICES,
+	SERVER_COUNT
+};
+
+// Aproximate systemd service states (see sd_notify)
+enum server_state {
+	SERVER_STOPPED,
+	SERVER_INIT,
+	SERVER_READY,
+	SERVER_RELOADING,
+	SERVER_STOPPING
+};
+
 typedef struct {
 
 	DWORD	size;				/* sizeof(bbs_struct_t) */
@@ -110,8 +128,7 @@ typedef struct {
 	int 	(*lputs)(void*, int , const char*);			/* Log - put string					*/
     int 	(*event_lputs)(void*, int, const char*);	/* Event log - put string			*/
 	void	(*errormsg)(void*, int level, const char* msg);
-	void	(*status)(void*, const char*);
-    void	(*started)(void*);
+	void	(*set_state)(void*, enum server_state);
 	void	(*recycle)(void*);
     void	(*terminated)(void*, int code);
     void	(*clients)(void*, int active);
diff --git a/src/sbbs3/websrvr.c b/src/sbbs3/websrvr.c
index 2455c0e398f9643e226c8dc3c20a5f839d4f62a3..b67973e53dd9230d3916d7e4877f47a1b8406c11 100644
--- a/src/sbbs3/websrvr.c
+++ b/src/sbbs3/websrvr.c
@@ -732,10 +732,10 @@ static char* server_host_name(void)
 	return startup->host_name[0] ? startup->host_name : scfg.sys_inetaddr;
 }
 
-static void status(char* str)
+static void set_state(enum server_state state)
 {
-	if(startup!=NULL && startup->status!=NULL)
-	    startup->status(startup->cbdata,str);
+	if(startup != NULL && startup->set_state != NULL)
+		startup->set_state(startup->cbdata, state);
 }
 
 static void update_clients(void)
@@ -6824,7 +6824,6 @@ static void cleanup(int code)
 #endif
 
 	thread_down();
-	status("Down");
 	if(terminate_server || code)
 		lprintf(LOG_INFO,"#### Web Server thread terminated (%lu clients served, %lu concurrently)"
 			,served, client_highwater);
@@ -7000,6 +6999,7 @@ void web_server(void* arg)
 		fprintf(stderr, "Invalid startup structure!\n");
 		return;
 	}
+	set_state(SERVER_INIT);
 
 #ifdef _THREAD_SUID_BROKEN
 	if(thread_suid_broken)
@@ -7039,8 +7039,6 @@ void web_server(void* arg)
 		(void)protected_uint32_adjust(&thread_count,1);
 		thread_up(FALSE /* setuid */);
 
-		status("Initializing");
-
 		/* Copy html directories */
 		SAFECOPY(root_dir,startup->root_dir);
 		SAFECOPY(error_dir,startup->error_dir);
@@ -7192,11 +7190,9 @@ void web_server(void* arg)
 		}
 
 		/* signal caller that we've started up successfully */
-		if(startup->started!=NULL)
-    		startup->started(startup->cbdata);
+		set_state(SERVER_READY);
 
 		lprintf(LOG_INFO,"Web Server thread started");
-		status("Listening");
 
 		while(!terminated && !terminate_server) {
 			YIELD();
@@ -7314,6 +7310,8 @@ void web_server(void* arg)
 			served++;
 		}
 
+		set_state(terminate_server ? SERVER_STOPPING : SERVER_RELOADING);
+
 		if(session) {
 			pthread_mutex_unlock(&session->struct_filled);
 			session=NULL;
@@ -7367,4 +7365,5 @@ void web_server(void* arg)
 	} while(!terminate_server);
 
 	protected_uint32_destroy(thread_count);
+	set_state(SERVER_STOPPED);
 }
diff --git a/src/sbbs3/websrvr.h b/src/sbbs3/websrvr.h
index 240acdfc2f57ee8316565b4553c7075c5df38e45..3229237bcdcc2ee1038bf56b0bf12f5cc13e5271 100644
--- a/src/sbbs3/websrvr.h
+++ b/src/sbbs3/websrvr.h
@@ -40,14 +40,13 @@ typedef struct {
 	uint16_t	tls_port;
     str_list_t	interfaces;
     str_list_t	tls_interfaces;
-	
+
 	void*	cbdata;				/* Private data passed to callbacks */ 
 
 	/* Callbacks (NULL if unused) */
 	int 	(*lputs)(void*, int level, const char* msg);
 	void	(*errormsg)(void*, int level, const char* msg);
-	void	(*status)(void*, const char*);
-    void	(*started)(void*);
+	void	(*set_state)(void*, enum server_state);
 	void	(*recycle)(void*);
     void	(*terminated)(void*, int code);
     void	(*clients)(void*, int active);