Newer
Older
/* ntsrvcs.c */
/* Synchronet BBS as a set of Windows NT Services */
/* $Id$ */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* Anonymous FTP access to the most recent released source is available at *
* ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
* *
* Anonymous CVS access to the development source and modification history *
* is available at cvs.synchro.net:/cvsroot/sbbs, example: *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login *
* (just hit return, no password is necessary) *
* cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* You are encouraged to submit any modifications (preferably in Unix diff *
* format) via e-mail to mods@synchro.net *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
/* Synchronet-specific headers */
#include "sbbs.h" /* various */
#include "sbbs_ini.h" /* sbbs_read_ini() */
#include "ftpsrvr.h" /* ftp_startup_t, ftp_server */
#include "websrvr.h" /* web_startup_t, web_server */
#include "mailsrvr.h" /* mail_startup_t, mail_server */
#include "services.h" /* services_startup_t, services_thread */
#include "ntsvcs.h" /* NT service names */
/* Windows-specific headers */
#include <winsvc.h>
#define NTSVC_TIMEOUT_STARTUP 30000 /* Milliseconds */
#define NTSVC_TIMEOUT_TERMINATE 30000 /* Milliseconds */
static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI web_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode);
static void WINAPI services_ctrl_handler(DWORD dwCtrlCode);
/* Global variables */
char ini_file[MAX_PATH+1];
bbs_startup_t bbs_startup;
ftp_startup_t ftp_startup;
mail_startup_t mail_startup;
services_startup_t services_startup;
web_startup_t web_startup;
typedef struct {
char* name;
char* display_name;
char* description;
void* startup;
BOOL* recycle_now;
void (*thread)(void* arg);
void (*terminate)(void);
void (WINAPI *ctrl_handler)(DWORD);
HANDLE log_handle;
BOOL autostart;
BOOL debug;
SERVICE_STATUS status;
SERVICE_STATUS_HANDLE status_handle;
} sbbs_ntsvc_t;
sbbs_ntsvc_t bbs ={
NTSVC_NAME_BBS,
"Synchronet Telnet/RLogin Server",
"Provides support for Telnet and RLogin clients and executes timed events. " \
"This service provides the critical functions of your Synchronet BBS.",
&bbs_startup,
&bbs_startup.recycle_now,
bbs_thread,
bbs_terminate,
bbs_ctrl_handler,
INVALID_HANDLE_VALUE
};
/* This is not (currently) a separate service, use this for logging only */
sbbs_ntsvc_t event ={
NTSVC_NAME_EVENT,
NULL,
NULL,
NULL,
NULL,
&bbs_startup.log_mask,
NULL,
NULL,
INVALID_HANDLE_VALUE
};
sbbs_ntsvc_t ftp = {
NTSVC_NAME_FTP,
"Synchronet FTP Server",
"Provides support for FTP clients (including web browsers) for file transfers.",
&ftp_startup,
&ftp_startup.recycle_now,
ftp_server,
ftp_terminate,
ftp_ctrl_handler,
INVALID_HANDLE_VALUE
};
sbbs_ntsvc_t web = {
NTSVC_NAME_WEB,
"Synchronet Web Server",
"Provides support for Web (HTML/HTTP) clients (browsers).",
&web_startup,
&web_startup.recycle_now,
web_server,
web_terminate,
web_ctrl_handler,
INVALID_HANDLE_VALUE
};
sbbs_ntsvc_t mail = {
NTSVC_NAME_MAIL,
"Synchronet SMTP/POP3 Mail Server",
"Sends and receives Internet e-mail (using SMTP) and allows users to remotely " \
"access their e-mail using an Internet mail client (using POP3).",
&mail_startup,
&mail_startup.recycle_now,
mail_server,
mail_terminate,
mail_ctrl_handler,
INVALID_HANDLE_VALUE
};
sbbs_ntsvc_t services = {
NTSVC_NAME_SERVICES,
"Synchronet Services",
"Plugin servers (usually in JavaScript) for any TCP/UDP protocol. " \
"Stock services include Finger, Gopher, NNTP, and IRC. Edit your ctrl/services.ini " \
"file for configuration of individual Synchronet Services.",
&services_startup,
&services_startup.recycle_now,
services_thread,
services_terminate,
services_ctrl_handler,
INVALID_HANDLE_VALUE
};
/* This list is used for enumerating all services */
sbbs_ntsvc_t* ntsvc_list[] = {
&bbs,
&ftp,
&web,
&mail,
&services,
NULL
};
/****************************************/
/* Service Control Handlers (Callbacks) */
/****************************************/
/* Common control handler for all services */
static void svc_ctrl_handler(sbbs_ntsvc_t* svc, DWORD dwCtrlCode)
{
switch(dwCtrlCode) {
case SERVICE_CONTROL_RECYCLE:
*svc->recycle_now=TRUE;
break;
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
svc->terminate();
svc->status.dwWaitHint=NTSVC_TIMEOUT_TERMINATE;
svc->status.dwCurrentState=SERVICE_STOP_PENDING;
break;
}
SetServiceStatus(svc->status_handle, &svc->status);
}
/* Service-specific control handler stub functions */
static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode)
{
svc_ctrl_handler(&bbs, dwCtrlCode);
}
static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode)
{
svc_ctrl_handler(&ftp, dwCtrlCode);
static void WINAPI web_ctrl_handler(DWORD dwCtrlCode)
svc_ctrl_handler(&web, dwCtrlCode);
static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode)
svc_ctrl_handler(&mail, dwCtrlCode);
static void WINAPI services_ctrl_handler(DWORD dwCtrlCode)
svc_ctrl_handler(&services, dwCtrlCode);
static WORD event_type(int level)
{
switch(level) {
case LOG_WARNING:
return(EVENTLOG_WARNING_TYPE);
case LOG_NOTICE:
case LOG_INFO:
case LOG_DEBUG:
return(EVENTLOG_INFORMATION_TYPE);
}
/*
LOG_EMERG
LOG_ALERT
LOG_CRIT
LOG_ERR
*/
return(EVENTLOG_ERROR_TYPE);
}
/**************************************/
/* Common Service Log Ouptut Function */
/**************************************/
static int svc_lputs(void* p, int level, char* str)
char debug[1024];
char fname[256];
DWORD len;
DWORD wr;
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
if(svc==NULL || svc->debug) {
snprintf(debug,sizeof(debug),"%s: %s",svc==NULL ? "Synchronet" : svc->name, str);
OutputDebugString(debug);
}
if(svc==NULL)
return(0);
len = strlen(str);
/* Mailslot Logging (for sbbsctrl) */
if(svc->log_handle != INVALID_HANDLE_VALUE /* Invalid log handle? */
&& !GetMailslotInfo(svc->log_handle, NULL, NULL, NULL, NULL)) {
/* Close and try to re-open */
CloseHandle(svc->log_handle);
svc->log_handle=INVALID_HANDLE_VALUE;
}
if(svc->log_handle == INVALID_HANDLE_VALUE) {
sprintf(fname,"\\\\.\\mailslot\\%s.log",svc->name);
svc->log_handle = CreateFile(
fname, // pointer to name of the file
GENERIC_WRITE, // access (read-write) mode
FILE_SHARE_READ, // share mode
NULL, // pointer to security attributes
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL // handle to file with attributes to copy
);
}
if(svc->log_handle != INVALID_HANDLE_VALUE) {
if(!WriteFile(svc->log_handle,str,len,&wr,NULL) || wr!=len) {
/* This most likely indicates the server closed the mailslot */
sprintf(debug,"!ERROR %d writing %u bytes to %s pipe (wr=%d)"
,GetLastError(),len,svc->name,wr);
OutputDebugString(debug);
/* So close the handle and attempt re-open next time */
CloseHandle(svc->log_handle);
svc->log_handle=INVALID_HANDLE_VALUE;
/* Event Logging */
if((*svc->log_mask)&(1<<level)) {
if(svc->event_handle == NULL)
svc->event_handle = RegisterEventSource(
NULL, // server name for source (NULL = local computer)
svc->name // source name for registered handle
);
if(svc->event_handle != NULL)
ReportEvent(svc->event_handle, // event log handle
event_type(level), // event type
0, // category zero
0, // event identifier
NULL, // no user security identifier
1, // one string
0, // no data
&str, // pointer to string array
NULL); // pointer to data
}
/****************************************************************************/
/* Event thread local/log print routine */
/****************************************************************************/
static int event_lputs(int level, char *str)
{
svc_lputs(&event,level,str);
return(0);
}
/************************************/
/* Shared Service Callback Routines */
/************************************/
static void svc_started(void* p)
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
svc->status.dwCurrentState=SERVICE_RUNNING;
svc->status.dwControlsAccepted|=SERVICE_ACCEPT_STOP;
SetServiceStatus(svc->status_handle, &svc->status);
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
static void svc_recycle(void *p)
{
char str[MAX_PATH*2];
FILE* fp;
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
bbs_startup_t* bbs_startup=NULL;
ftp_startup_t* ftp_startup=NULL;
mail_startup_t* mail_startup=NULL;
services_startup_t* services_startup=NULL;
web_startup_t* web_startup=NULL;
if(svc==&bbs)
bbs_startup=svc->startup;
else if(svc==&ftp)
ftp_startup=svc->startup;
else if(svc==&web)
web_startup=svc->startup;
else if(svc==&mail)
mail_startup=svc->startup;
else if(svc==&services)
services_startup=svc->startup;
SAFEPRINTF(str,"Reading %s",ini_file);
svc_lputs(svc,LOG_INFO,str);
/* Read .ini file here */
fp=fopen(ini_file,"r");
/* We call this function to set defaults, even if there's no .ini file */
sbbs_read_ini(fp
,NULL /* global_startup */
,NULL ,bbs_startup
,NULL ,ftp_startup
,NULL ,web_startup
,NULL ,mail_startup
,NULL ,services_startup
);
/* close .ini file here */
if(fp!=NULL)
fclose(fp);
}
static void svc_terminated(void* p, int code)
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
if(code) {
svc->status.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;
svc->status.dwServiceSpecificExitCode=code;
SetServiceStatus(svc->status_handle, &svc->status);
static void svc_clients(void* p, int active)
{
sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
}
/***************/
/* ServiceMain */
/***************/
/* Common ServiceMain for all services */
static void WINAPI svc_main(sbbs_ntsvc_t* svc, DWORD argc, LPTSTR *argv)
char str[256];
DWORD i;
char* arg;
for(i=0;i<argc;i++) {
arg=argv[i];
if(*arg=='-' || *arg=='/')
arg++;
if(!stricmp(arg,"debug"))
svc->debug=TRUE;
if(!stricmp(arg,"logmask") && i+1<argc)
(*svc->log_mask)=strtol(argv[++i],NULL,0);
}
sprintf(str,"Starting NT Service: %s",svc->display_name);
svc_lputs(svc,LOG_INFO,str);
if((svc->status_handle = RegisterServiceCtrlHandler(svc->name, svc->ctrl_handler))==0) {
sprintf(str,"!ERROR %d registering service control handler",GetLastError());
svc_lputs(NULL,LOG_ERR,str);
memset(&svc->status,0,sizeof(SERVICE_STATUS));
svc->status.dwServiceType=SERVICE_WIN32_SHARE_PROCESS;
svc->status.dwControlsAccepted=SERVICE_ACCEPT_SHUTDOWN;
svc->status.dwWaitHint=NTSVC_TIMEOUT_STARTUP;
svc->status.dwCurrentState=SERVICE_START_PENDING;
SetServiceStatus(svc->status_handle, &svc->status);
svc->status.dwCurrentState=SERVICE_STOPPED;
SetServiceStatus(svc->status_handle, &svc->status);
if(svc->log_handle!=INVALID_HANDLE_VALUE) {
CloseHandle(svc->log_handle);
svc->log_handle=INVALID_HANDLE_VALUE;
if(svc->event_handle!=NULL) {
DeregisterEventSource(svc->event_handle);
svc->event_handle=NULL;
}
/* Service-specific ServiceMain stub functions */
static void WINAPI bbs_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&bbs, dwArgc, lpszArgv);
/* Events are (currently) part of the BBS service */
if(event.log_handle!=INVALID_HANDLE_VALUE) {
CloseHandle(event.log_handle);
event.log_handle=INVALID_HANDLE_VALUE;
}
static void WINAPI ftp_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&ftp, dwArgc, lpszArgv);
static void WINAPI web_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&web, dwArgc, lpszArgv);
static void WINAPI mail_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&mail, dwArgc, lpszArgv);
static void WINAPI services_start(DWORD dwArgc, LPTSTR *lpszArgv)
svc_main(&services, dwArgc, lpszArgv);
}
/******************************************/
/* NT Serivce Install/Uninstall Functions */
/******************************************/
/* ChangeServiceConfig2 is a Win2K+ API function, must call dynamically */
typedef WINADVAPI BOOL (WINAPI *ChangeServiceConfig2_t)(SC_HANDLE, DWORD, LPCVOID);
static void describe_service(HANDLE hSCMlib, SC_HANDLE hService, char* description)
{
ChangeServiceConfig2_t changeServiceConfig2;
static SERVICE_DESCRIPTION service_desc;
if(hSCMlib==NULL)
return;
service_desc.lpDescription=description;
if((changeServiceConfig2 = (ChangeServiceConfig2_t)GetProcAddress(hSCMlib, "ChangeServiceConfig2A"))!=NULL)
changeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &service_desc);
}
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
static BOOL register_event_source(char* name, char* path)
{
char keyname[256];
HKEY hKey;
DWORD type;
DWORD disp;
LONG retval;
char* value;
sprintf(keyname,"system\\CurrentControlSet\\services\\eventlog\\application\\%s",name);
retval=RegCreateKeyEx(
HKEY_LOCAL_MACHINE, // handle to an open key
keyname, // address of subkey name
0, // reserved
"", // address of class string
0, // special options flag
KEY_ALL_ACCESS, // desired security access
NULL, // address of key security structure
&hKey, // address of buffer for opened handle
&disp // address of disposition value buffer
);
if(retval!=ERROR_SUCCESS) {
fprintf(stderr,"!Error %d creating/opening registry key (HKLM\\%s)\n"
,retval,keyname);
return(FALSE);
}
value="EventMessageFile";
retval=RegSetValueEx(
hKey, // handle to key to set value for
value, // name of the value to set
0, // reserved
REG_SZ, // flag for value type
path, // address of value data
strlen(path) // size of value data
);
if(retval!=ERROR_SUCCESS) {
RegCloseKey(hKey);
fprintf(stderr,"!Error %d setting registry key value (%s)\n"
,retval,value);
return(FALSE);
}
value="TypesSupported";
type=EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
retval=RegSetValueEx(
hKey, // handle to key to set value for
value, // name of the value to set
0, // reserved
REG_DWORD, // flag for value type
(BYTE*)&type, // address of value data
sizeof(type) // size of value data
);
RegCloseKey(hKey);
if(retval!=ERROR_SUCCESS) {
fprintf(stderr,"!Error %d setting registry key value (%s)\n"
,retval,value);
return(FALSE);
}
return(TRUE);
}
/****************************************************************************/
/* Utility function to create a service with description (on Win2K+) */
/****************************************************************************/
static SC_HANDLE create_service(HANDLE hSCMlib, SC_HANDLE hSCManager
,char* name, char* display_name, char* description, char* path
,BOOL autostart)
printf("Installing service: %-40s ... ", display_name);
hSCManager, // SCManager database
name, // name of service
display_name, // name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_SHARE_PROCESS, // service type
autostart // start type (auto or manual)
? SERVICE_AUTO_START : SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL, // error control type
path, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
"", // dependencies
NULL, // LocalSystem account
NULL); // no password
if(hService==NULL)
printf("!ERROR %d\n",GetLastError());
else {
describe_service(hSCMlib, hService,description);
CloseServiceHandle(hService);
printf("Successful\n");
register_event_source(name,path);
/****************************************************************************/
/* Install one or all services */
/****************************************************************************/
int i;
HANDLE hSCMlib;
SC_HANDLE hSCManager;
char path[MAX_PATH+1];
printf("Installing Synchronet NT Services...\n");
hSCMlib = LoadLibrary("ADVAPI32.DLL");
if(GetModuleFileName(NULL,path,sizeof(path))==0)
{
fprintf(stderr,"!ERROR %d getting module file name\n",GetLastError());
return(-1);
}
hSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if(hSCManager==NULL) {
fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
return(-1);
}
for(i=0;ntsvc_list[i]!=NULL;i++)
if(svc_name==NULL /* All? */
|| !stricmp(ntsvc_list[i]->name, svc_name))
create_service(hSCMlib
,hSCManager
,ntsvc_list[i]->name
,ntsvc_list[i]->display_name
,ntsvc_list[i]->description
,path
,ntsvc_list[i]->autostart);
if(hSCMlib!=NULL)
FreeLibrary(hSCMlib);
CloseServiceHandle(hSCManager);
return(0);
}
/****************************************************************************/
/* Utility function to remove a service cleanly (stopping if necessary) */
/****************************************************************************/
static void remove_service(SC_HANDLE hSCManager, char* name, char* disp_name)
{
SC_HANDLE hService;
SERVICE_STATUS status;
printf("Removing service: %-40s ... ", disp_name);
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS);
if(hService==NULL) {
printf("\n!ERROR %d opening service: %s\n",GetLastError(),name);
return;
}
// try to stop the service
if(ControlService( hService, SERVICE_CONTROL_STOP, &status))
{
printf("\nStopping: %s ... ",name);
while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING)
Sleep(1000);
if(status.dwCurrentState == SERVICE_STOPPED)
printf("Stopped.\n");
else
printf("FAILED!\n");
}
// now remove the service
if(DeleteService(hService))
printf("Successful\n");
else
printf("!ERROR %d\n",GetLastError());
CloseServiceHandle(hService);
}
/****************************************************************************/
/* Uninstall one or all services */
/****************************************************************************/
int i;
SC_HANDLE hSCManager;
hSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if(hSCManager==NULL) {
fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
return(-1);
}
for(i=0;ntsvc_list[i]!=NULL;i++)
if(svc_name==NULL /* All? */
|| !stricmp(ntsvc_list[i]->name, svc_name))
remove_service(hSCManager
,ntsvc_list[i]->name
,ntsvc_list[i]->display_name);
CloseServiceHandle(hSCManager);
return(0);
}
/****************************************************************************/
/* Utility function to disable a service */
/****************************************************************************/
static void set_service_start_type(SC_HANDLE hSCManager, char* name
,char* disp_name, DWORD start_type)
{
SC_HANDLE hService;
printf("%s service: %-40s ... "
,start_type==SERVICE_DISABLED ? "Disabling" : "Enabling", disp_name);
hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS);
if(hService==NULL) {
printf("\n!ERROR %d opening service: %s\n",GetLastError(),name);
return;
}
if(!ChangeServiceConfig(
hService, // handle to service
SERVICE_NO_CHANGE, // type of service
start_type, // when to start service
SERVICE_NO_CHANGE, // severity if service fails to start
NULL, // pointer to service binary file name
NULL, // pointer to load ordering group name
NULL, // pointer to variable to get tag identifier
NULL, // pointer to array of dependency names
NULL, // pointer to account name of service
NULL, // pointer to password for service account
NULL // pointer to display name
))
printf("\n!ERROR %d changing service config for: %s\n",GetLastError(),name);
else
printf("Successful\n");
CloseServiceHandle(hService);
}
/****************************************************************************/
/* Enable (set to auto-start) or disable one or all services */
/****************************************************************************/
static int enable(const char* svc_name, BOOL enabled)
{
int i;
SC_HANDLE hSCManager;
hSCManager = OpenSCManager(
NULL, // machine (NULL == local)
NULL, // database (NULL == default)
SC_MANAGER_ALL_ACCESS // access required
);
if(hSCManager==NULL) {
fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
return(-1);
}
for(i=0;ntsvc_list[i]!=NULL;i++)
if(svc_name==NULL /* All? */
|| !stricmp(ntsvc_list[i]->name, svc_name))
set_service_start_type(hSCManager
,ntsvc_list[i]->name
,ntsvc_list[i]->display_name
,enabled ? SERVICE_AUTO_START : SERVICE_DISABLED);
CloseServiceHandle(hSCManager);
return(0);
}
/****************************************************************************/
/* Main Entry Point */
/****************************************************************************/
int main(int argc, char** argv)
{
char* ctrl_dir;
char* p;
FILE* fp=NULL;
SERVICE_TABLE_ENTRY ServiceDispatchTable[] =
{
{ bbs.name, bbs_start },
{ ftp.name, ftp_start },
{ web.name, web_start },
{ mail.name, mail_start },
{ services.name, services_start },
{ NULL, NULL } /* Terminator */
};
printf("\nSynchronet NT Services Version %s%c %s\n\n"
,VERSION,REVISION,COPYRIGHT_NOTICE);
ctrl_dir=getenv("SBBSCTRL"); /* read from environment variable */
if(ctrl_dir==NULL || ctrl_dir[0]==0) {
ctrl_dir="\\sbbs\\ctrl"; /* Not set? Use default */
printf("!SBBSCTRL environment variable not set, using default value: %s\n\n"
,ctrl_dir);
}
sbbs_get_ini_fname(ini_file, ctrl_dir, NULL /* auto-host_name */);
/* Initialize BBS startup structure */
memset(&bbs_startup,0,sizeof(bbs_startup));
bbs_startup.size=sizeof(bbs_startup);
bbs_startup.lputs=svc_lputs;
bbs_startup.event_lputs=event_lputs;
bbs_startup.started=svc_started;
bbs_startup.recycle=svc_recycle;
bbs_startup.terminated=svc_terminated;
bbs_startup.clients=svc_clients;
strcpy(bbs_startup.ctrl_dir,ctrl_dir);
/* Initialize FTP startup structure */
memset(&ftp_startup,0,sizeof(ftp_startup));
ftp_startup.lputs=svc_lputs;
ftp_startup.started=svc_started;
ftp_startup.recycle=svc_recycle;
ftp_startup.terminated=svc_terminated;
ftp_startup.clients=svc_clients;
strcpy(ftp_startup.ctrl_dir,ctrl_dir);
/* Initialize Web Server startup structure */
memset(&web_startup,0,sizeof(web_startup));
web_startup.lputs=svc_lputs;
web_startup.started=svc_started;
web_startup.recycle=svc_recycle;
web_startup.terminated=svc_terminated;
web_startup.clients=svc_clients;
strcpy(web_startup.ctrl_dir,ctrl_dir);
/* Initialize Mail Server startup structure */
memset(&mail_startup,0,sizeof(mail_startup));
mail_startup.size=sizeof(mail_startup);
mail_startup.lputs=svc_lputs;
mail_startup.started=svc_started;
mail_startup.recycle=svc_recycle;
mail_startup.terminated=svc_terminated;
mail_startup.clients=svc_clients;
strcpy(mail_startup.ctrl_dir,ctrl_dir);
/* Initialize Services startup structure */
memset(&services_startup,0,sizeof(services_startup));
services_startup.size=sizeof(services_startup);
services_startup.lputs=svc_lputs;
services_startup.started=svc_started;
services_startup.recycle=svc_recycle;
services_startup.terminated=svc_terminated;
services_startup.clients=svc_clients;
strcpy(services_startup.ctrl_dir,ctrl_dir);
/* Read .ini file here */
if((fp=fopen(ini_file,"r"))!=NULL) {
svc_lputs(NULL,LOG_INFO,str);
}
/* We call this function to set defaults, even if there's no .ini file */
sbbs_read_ini(fp
,NULL /* global_startup */
,&bbs.autostart ,&bbs_startup
,&ftp.autostart ,&ftp_startup
,&web.autostart ,&web_startup
,&mail.autostart ,&mail_startup
,&services.autostart ,&services_startup
);
/* close .ini file here */
if(fp!=NULL)
fclose(fp);
ctrl_dir = bbs_startup.ctrl_dir;
if(chdir(ctrl_dir)!=0) {
sprintf(str,"!ERROR %d changing directory to: %s", errno, ctrl_dir);
svc_lputs(NULL,LOG_ERR,str);
for(i=1;i<argc;i++) {
arg=argv[i];
while(*arg=='-')
arg++;
if(!stricmp(arg,"install"))
return install(argv[i+1]);
if(!stricmp(arg,"remove"))
return uninstall(argv[i+1]);
if(!stricmp(arg,"disable"))
return enable(argv[i+1], FALSE);
if(!stricmp(arg,"enable"))
return enable(argv[i+1], TRUE);
}
printf("Available Services:\n\n");
printf("%-20s %s\n","Name","Description");
printf("%-20s %s\n","----","-----------");
for(i=0;ntsvc_list[i]!=NULL;i++)
printf("%-20s %s\n",ntsvc_list[i]->name,ntsvc_list[i]->display_name);
SAFECOPY(str,getfname(argv[0]));
if((p=getfext(str))!=NULL)
*p=0;
printf("\nUsage: %s [command] [service]\n", str);
printf("\nCommands:\n");
printf("\tinstall\t to install a service by name (default: ALL services)\n");
printf("\tremove\t to remove a service by name (default: ALL services)\n");
printf("\tdisable\t to disable a service by name (default: ALL services)\n");
printf("\tenable\t to re-enable a disabled service (default: ALL services)\n");
printf("\nStartServiceCtrlDispatcher being called.\n" );
printf("This may take several seconds. Please wait.\n" );
if(!StartServiceCtrlDispatcher(ServiceDispatchTable))
{
sprintf(str,"!StartServiceCtrlDispatcher ERROR %d",GetLastError());