|
|
1.1 root 1: /* ntsvcs.c */
2:
3: /* Synchronet BBS as a set of Windows NT Services */
4:
5: /* $Id: ntsvcs.c,v 1.35 2006/12/31 00:07:50 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: /* Synchronet-specific headers */
39: #include "sbbs.h" /* various */
40: #include "sbbs_ini.h" /* sbbs_read_ini() */
41: #include "ftpsrvr.h" /* ftp_startup_t, ftp_server */
42: #include "websrvr.h" /* web_startup_t, web_server */
43: #include "mailsrvr.h" /* mail_startup_t, mail_server */
44: #include "services.h" /* services_startup_t, services_thread */
45: #include "ntsvcs.h" /* NT service names */
46:
47: /* Windows-specific headers */
48: #include <winsvc.h>
49:
50: #define NTSVC_TIMEOUT_STARTUP 30000 /* Milliseconds */
51: #define NTSVC_TIMEOUT_TERMINATE 30000 /* Milliseconds */
52:
53: #define STRLEN_MAX_DISPLAY_NAME 35
54:
55: #define STRLEN_SYNCHRONET 10 /* this number ain't change'n */
56:
57: #define SERVICE_NOT_INSTALLED (SERVICE_DISABLED+1)
58:
59: static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode);
60: static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode);
61: static void WINAPI web_ctrl_handler(DWORD dwCtrlCode);
62: static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode);
63: static void WINAPI services_ctrl_handler(DWORD dwCtrlCode);
64:
65: /* Global variables */
66:
67: char ini_file[MAX_PATH+1];
68: bbs_startup_t bbs_startup;
69: ftp_startup_t ftp_startup;
70: mail_startup_t mail_startup;
71: services_startup_t services_startup;
72: web_startup_t web_startup;
73:
74: typedef struct {
75: char* name;
76: char* display_name;
77: char* description;
78: void* startup;
79: DWORD* options;
80: BOOL* recycle_now;
81: int* log_level;
82: void DLLCALL (*thread)(void* arg);
83: void DLLCALL (*terminate)(void);
84: void (WINAPI *ctrl_handler)(DWORD);
85: HANDLE log_handle;
86: HANDLE event_handle;
87: BOOL autostart;
88: BOOL debug;
89: SERVICE_STATUS status;
90: SERVICE_STATUS_HANDLE status_handle;
91: } sbbs_ntsvc_t;
92:
93: sbbs_ntsvc_t bbs ={
94: NTSVC_NAME_BBS,
95: "Synchronet Telnet/RLogin/SSH Server",
96: "Provides support for Telnet, RLogin, and SSH clients and executes timed events. " \
97: "This service provides the critical functions of your Synchronet BBS.",
98: &bbs_startup,
99: &bbs_startup.options,
100: &bbs_startup.recycle_now,
101: &bbs_startup.log_level,
102: bbs_thread,
103: bbs_terminate,
104: bbs_ctrl_handler,
105: INVALID_HANDLE_VALUE
106: };
107:
108: /* This is not (currently) a separate service, use this for logging only */
109: sbbs_ntsvc_t event ={
110: NTSVC_NAME_EVENT,
111: NULL,
112: NULL,
113: NULL,
114: NULL,
115: NULL,
116: &bbs_startup.log_level,
117: NULL,
118: NULL,
119: NULL,
120: INVALID_HANDLE_VALUE
121: };
122:
123: sbbs_ntsvc_t ftp = {
124: NTSVC_NAME_FTP,
125: "Synchronet FTP Server",
126: "Provides support for FTP clients (including web browsers) for file transfers.",
127: &ftp_startup,
128: &ftp_startup.options,
129: &ftp_startup.recycle_now,
130: &ftp_startup.log_level,
131: ftp_server,
132: ftp_terminate,
133: ftp_ctrl_handler,
134: INVALID_HANDLE_VALUE
135: };
136:
137: sbbs_ntsvc_t web = {
138: NTSVC_NAME_WEB,
139: "Synchronet Web Server",
140: "Provides support for Web (HTML/HTTP) clients (browsers).",
141: &web_startup,
142: &web_startup.options,
143: &web_startup.recycle_now,
144: &web_startup.log_level,
145: web_server,
146: web_terminate,
147: web_ctrl_handler,
148: INVALID_HANDLE_VALUE
149: };
150:
151: sbbs_ntsvc_t mail = {
152: NTSVC_NAME_MAIL,
153: "Synchronet SMTP/POP3 Mail Server",
154: "Sends and receives Internet e-mail (using SMTP) and allows users to remotely " \
155: "access their e-mail using an Internet mail client (using POP3).",
156: &mail_startup,
157: &mail_startup.options,
158: &mail_startup.recycle_now,
159: &mail_startup.log_level,
160: mail_server,
161: mail_terminate,
162: mail_ctrl_handler,
163: INVALID_HANDLE_VALUE
164: };
165:
166: sbbs_ntsvc_t services = {
167: NTSVC_NAME_SERVICES,
168: "Synchronet Services",
169: "Plugin servers (usually in JavaScript) for any TCP/UDP protocol. " \
170: "Stock services include Finger, Gopher, NNTP, and IRC. Edit your ctrl/services.ini " \
171: "file for configuration of individual Synchronet Services.",
172: &services_startup,
173: &services_startup.options,
174: &services_startup.recycle_now,
175: &services_startup.log_level,
176: services_thread,
177: services_terminate,
178: services_ctrl_handler,
179: INVALID_HANDLE_VALUE
180: };
181:
182: /* This list is used for enumerating all services */
183: sbbs_ntsvc_t* ntsvc_list[] = {
184: &bbs,
185: &ftp,
186: &web,
187: &mail,
188: &services,
189: NULL
190: };
191:
192: /****************************************/
193: /* Service Control Handlers (Callbacks) */
194: /****************************************/
195:
196: /* Common control handler for all services */
197: static void svc_ctrl_handler(sbbs_ntsvc_t* svc, DWORD dwCtrlCode)
198: {
199: switch(dwCtrlCode) {
200: case SERVICE_CONTROL_RECYCLE:
201: *svc->recycle_now=TRUE;
202: break;
203: case SERVICE_CONTROL_MUTE:
204: *svc->options|=BBS_OPT_MUTE;
205: break;
206: case SERVICE_CONTROL_UNMUTE:
207: *svc->options&=~BBS_OPT_MUTE;
208: break;
209: case SERVICE_CONTROL_STOP:
210: case SERVICE_CONTROL_SHUTDOWN:
211: svc->terminate();
212: svc->status.dwWaitHint=NTSVC_TIMEOUT_TERMINATE;
213: svc->status.dwCurrentState=SERVICE_STOP_PENDING;
214: break;
215: }
216: SetServiceStatus(svc->status_handle, &svc->status);
217: }
218:
219: /* Service-specific control handler stub functions */
220: static void WINAPI bbs_ctrl_handler(DWORD dwCtrlCode)
221: {
222: switch(dwCtrlCode) {
223: case SERVICE_CONTROL_SYSOP_AVAILABLE:
224: bbs_startup.options|=BBS_OPT_SYSOP_AVAILABLE;
225: break;
226: case SERVICE_CONTROL_SYSOP_UNAVAILABLE:
227: bbs_startup.options&=~BBS_OPT_SYSOP_AVAILABLE;
228: break;
229: default:
230: svc_ctrl_handler(&bbs, dwCtrlCode);
231: break;
232: }
233: }
234:
235: static void WINAPI ftp_ctrl_handler(DWORD dwCtrlCode)
236: {
237: svc_ctrl_handler(&ftp, dwCtrlCode);
238: }
239:
240: static void WINAPI web_ctrl_handler(DWORD dwCtrlCode)
241: {
242: svc_ctrl_handler(&web, dwCtrlCode);
243: }
244:
245: static void WINAPI mail_ctrl_handler(DWORD dwCtrlCode)
246: {
247: svc_ctrl_handler(&mail, dwCtrlCode);
248: }
249:
250: static void WINAPI services_ctrl_handler(DWORD dwCtrlCode)
251: {
252: svc_ctrl_handler(&services, dwCtrlCode);
253: }
254:
255: static WORD event_type(int level)
256: {
257: switch(level) {
258: case LOG_WARNING:
259: return(EVENTLOG_WARNING_TYPE);
260: case LOG_NOTICE:
261: case LOG_INFO:
262: case LOG_DEBUG:
263: return(EVENTLOG_INFORMATION_TYPE); /* same as EVENT_LOG_SUCCESS */
264: }
265: /*
266: LOG_EMERG
267: LOG_ALERT
268: LOG_CRIT
269: LOG_ERR
270: */
271: return(EVENTLOG_ERROR_TYPE);
272: }
273:
274: /**************************************/
275: /* Common Service Log Ouptut Function */
276: /**************************************/
277: static int svc_lputs(void* p, int level, char* str)
278: {
279: char debug[1024];
280: char fname[256];
281: DWORD len;
282: DWORD wr;
283: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
284:
285: /* Debug Logging */
286: if(svc==NULL || svc->debug) {
287: snprintf(debug,sizeof(debug),"%s: %s",svc==NULL ? "Synchronet" : svc->name, str);
288: OutputDebugString(debug);
289: }
290: if(svc==NULL)
291: return(0);
292:
293: len = strlen(str);
294:
295: /* Mailslot Logging (for sbbsctrl) */
296: if(svc->log_handle != INVALID_HANDLE_VALUE /* Invalid log handle? */
297: && !GetMailslotInfo(svc->log_handle, NULL, NULL, NULL, NULL)) {
298: /* Close and try to re-open */
299: CloseHandle(svc->log_handle);
300: svc->log_handle=INVALID_HANDLE_VALUE;
301: }
302:
303: if(svc->log_handle == INVALID_HANDLE_VALUE) {
304: sprintf(fname,"\\\\.\\mailslot\\%s.log",svc->name);
305: svc->log_handle = CreateFile(
306: fname, /* pointer to name of the file */
307: GENERIC_WRITE, /* access (read-write) mode */
308: FILE_SHARE_READ, /* share mode */
309: NULL, /* pointer to security attributes */
310: OPEN_EXISTING, /* how to create */
311: FILE_ATTRIBUTE_NORMAL, /* file attributes */
312: NULL /* handle to file with attributes to copy */
313: );
314: }
315: if(svc->log_handle != INVALID_HANDLE_VALUE) {
316: if(!WriteFile(svc->log_handle,str,len,&wr,NULL) || wr!=len) {
317: /* This most likely indicates the server closed the mailslot */
318: sprintf(debug,"!ERROR %d writing %u bytes to %s pipe (wr=%d)"
319: ,GetLastError(),len,svc->name,wr);
320: OutputDebugString(debug);
321: /* So close the handle and attempt re-open next time */
322: CloseHandle(svc->log_handle);
323: svc->log_handle=INVALID_HANDLE_VALUE;
324: }
325: }
326:
327: /* Event Logging */
328: if(level <= (*svc->log_level)) {
329: if(svc->event_handle == NULL)
330: svc->event_handle = RegisterEventSource(
331: NULL, /* server name for source (NULL = local computer) */
332: svc->name /* source name for registered handle */
333: );
334: if(svc->event_handle != NULL)
335: ReportEvent(svc->event_handle, /* event log handle */
336: event_type(level), /* event type */
337: 0, /* category zero */
338: 0, /* event identifier */
339: NULL, /* no user security identifier */
340: 1, /* one string */
341: 0, /* no data */
342: (LPCSTR*)&str, /* pointer to string array */
343: NULL); /* pointer to data */
344: }
345:
346: return(0);
347: }
348:
349: /****************************************************************************/
350: /* Event thread local/log print routine */
351: /****************************************************************************/
352: static int event_lputs(int level, char *str)
353: {
354: svc_lputs(&event,level,str);
355: return(0);
356: }
357:
358: /************************************/
359: /* Shared Service Callback Routines */
360: /************************************/
361:
362: static void svc_started(void* p)
363: {
364: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
365:
366: svc->status.dwCurrentState=SERVICE_RUNNING;
367: svc->status.dwControlsAccepted|=SERVICE_ACCEPT_STOP;
368: SetServiceStatus(svc->status_handle, &svc->status);
369: }
370:
371: static void read_ini(sbbs_ntsvc_t* svc)
372: {
373: char str[MAX_PATH*2];
374: FILE* fp;
375: bbs_startup_t* bbs_startup=NULL;
376: ftp_startup_t* ftp_startup=NULL;
377: mail_startup_t* mail_startup=NULL;
378: services_startup_t* services_startup=NULL;
379: web_startup_t* web_startup=NULL;
380:
381: if(svc==&bbs)
382: bbs_startup=svc->startup;
383: else if(svc==&ftp)
384: ftp_startup=svc->startup;
385: else if(svc==&web)
386: web_startup=svc->startup;
387: else if(svc==&mail)
388: mail_startup=svc->startup;
389: else if(svc==&services)
390: services_startup=svc->startup;
391:
392: if((fp=fopen(ini_file,"r"))!=NULL) {
393: sprintf(str,"Reading %s",ini_file);
394: svc_lputs(NULL,LOG_INFO,str);
395: }
396:
397: /* We call this function to set defaults, even if there's no .ini file */
398: sbbs_read_ini(fp
399: ,NULL /* global_startup */
400: ,NULL ,bbs_startup
401: ,NULL ,ftp_startup
402: ,NULL ,web_startup
403: ,NULL ,mail_startup
404: ,NULL ,services_startup
405: );
406:
407: /* close .ini file here */
408: if(fp!=NULL)
409: fclose(fp);
410: }
411:
412: static void svc_recycle(void *p)
413: {
414: read_ini((sbbs_ntsvc_t*)p);
415: }
416:
417: static void svc_terminated(void* p, int code)
418: {
419: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
420:
421: if(code) {
422: svc->status.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;
423: svc->status.dwServiceSpecificExitCode=code;
424: SetServiceStatus(svc->status_handle, &svc->status);
425: }
426: }
427:
428: static void svc_clients(void* p, int active)
429: {
430: sbbs_ntsvc_t* svc = (sbbs_ntsvc_t*)p;
431: }
432:
433: /***************/
434: /* ServiceMain */
435: /***************/
436:
437: /* Common ServiceMain for all services */
438: static void WINAPI svc_main(sbbs_ntsvc_t* svc, DWORD argc, LPTSTR *argv)
439: {
440: char str[256];
441: DWORD i;
442: char* arg;
443:
444: for(i=0;i<argc;i++) {
445: arg=argv[i];
446: if(*arg=='-' || *arg=='/')
447: arg++;
448: if(!stricmp(arg,"debug"))
449: svc->debug=TRUE;
450: if(!stricmp(arg,"loglevel") && i+1<argc)
451: (*svc->log_level)=strtol(argv[++i],NULL,0);
452: }
453:
454: sprintf(str,"Starting NT Service: %s",svc->display_name);
455: svc_lputs(svc,LOG_INFO,str);
456:
457: if((svc->status_handle = RegisterServiceCtrlHandler(svc->name, svc->ctrl_handler))==0) {
458: sprintf(str,"!ERROR %d registering service control handler",GetLastError());
459: svc_lputs(NULL,LOG_ERR,str);
460: return;
461: }
462:
463: memset(&svc->status,0,sizeof(SERVICE_STATUS));
464: svc->status.dwServiceType=SERVICE_WIN32_SHARE_PROCESS;
465: svc->status.dwControlsAccepted=SERVICE_ACCEPT_SHUTDOWN;
466: svc->status.dwWaitHint=NTSVC_TIMEOUT_STARTUP;
467:
468: svc->status.dwCurrentState=SERVICE_START_PENDING;
469: SetServiceStatus(svc->status_handle, &svc->status);
470:
471: read_ini(svc);
472:
473: svc->thread(svc->startup);
474:
475: svc->status.dwCurrentState=SERVICE_STOPPED;
476: SetServiceStatus(svc->status_handle, &svc->status);
477:
478: if(svc->log_handle!=INVALID_HANDLE_VALUE) {
479: CloseHandle(svc->log_handle);
480: svc->log_handle=INVALID_HANDLE_VALUE;
481: }
482:
483: if(svc->event_handle!=NULL) {
484: DeregisterEventSource(svc->event_handle);
485: svc->event_handle=NULL;
486: }
487: }
488:
489: /* Service-specific ServiceMain stub functions */
490:
491: static void WINAPI bbs_start(DWORD dwArgc, LPTSTR *lpszArgv)
492: {
493: svc_main(&bbs, dwArgc, lpszArgv);
494:
495: /* Events are (currently) part of the BBS service */
496: if(event.log_handle!=INVALID_HANDLE_VALUE) {
497: CloseHandle(event.log_handle);
498: event.log_handle=INVALID_HANDLE_VALUE;
499: }
500: }
501:
502: static void WINAPI ftp_start(DWORD dwArgc, LPTSTR *lpszArgv)
503: {
504: svc_main(&ftp, dwArgc, lpszArgv);
505: }
506:
507: static void WINAPI web_start(DWORD dwArgc, LPTSTR *lpszArgv)
508: {
509: svc_main(&web, dwArgc, lpszArgv);
510: }
511:
512: static void WINAPI mail_start(DWORD dwArgc, LPTSTR *lpszArgv)
513: {
514: svc_main(&mail, dwArgc, lpszArgv);
515: }
516:
517: static void WINAPI services_start(DWORD dwArgc, LPTSTR *lpszArgv)
518: {
519: svc_main(&services, dwArgc, lpszArgv);
520: }
521:
522: /******************************************/
523: /* NT Serivce Install/Uninstall Functions */
524: /******************************************/
525:
526: /* ChangeServiceConfig2 is a Win2K+ API function, must call dynamically */
527: typedef WINADVAPI BOOL (WINAPI *ChangeServiceConfig2_t)(SC_HANDLE, DWORD, LPCVOID);
528:
529: static void describe_service(HANDLE hSCMlib, SC_HANDLE hService, char* description)
530: {
531: ChangeServiceConfig2_t changeServiceConfig2;
532: static SERVICE_DESCRIPTION service_desc;
533:
534: if(hSCMlib==NULL)
535: return;
536:
537: service_desc.lpDescription=description;
538:
539: if((changeServiceConfig2 = (ChangeServiceConfig2_t)GetProcAddress(hSCMlib, "ChangeServiceConfig2A"))!=NULL)
540: changeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &service_desc);
541: }
542:
543: static BOOL register_event_source(char* name, char* path)
544: {
545: char keyname[256];
546: HKEY hKey;
547: DWORD type;
548: DWORD disp;
549: LONG retval;
550: char* value;
551:
552: sprintf(keyname,"system\\CurrentControlSet\\services\\eventlog\\application\\%s",name);
553:
554: retval=RegCreateKeyEx(
555: HKEY_LOCAL_MACHINE, /* handle to an open key */
556: keyname, /* address of subkey name */
557: 0, /* reserved */
558: "", /* address of class string */
559: 0, /* special options flag */
560: KEY_ALL_ACCESS, /* desired security access */
561: NULL, /* address of key security structure */
562: &hKey, /* address of buffer for opened handle */
563: &disp /* address of disposition value buffer */
564: );
565:
566: if(retval!=ERROR_SUCCESS) {
567: fprintf(stderr,"!Error %d creating/opening registry key (HKLM\\%s)\n"
568: ,retval,keyname);
569: return(FALSE);
570: }
571:
572: value="EventMessageFile";
573: retval=RegSetValueEx(
574: hKey, /* handle to key to set value for */
575: value, /* name of the value to set */
576: 0, /* reserved */
577: REG_SZ, /* flag for value type */
578: path, /* address of value data */
579: strlen(path) /* size of value data */
580: );
581:
582: if(retval!=ERROR_SUCCESS) {
583: RegCloseKey(hKey);
584: fprintf(stderr,"!Error %d setting registry key value (%s)\n"
585: ,retval,value);
586: return(FALSE);
587: }
588:
589: value="TypesSupported";
590: type=EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
591: retval=RegSetValueEx(
592: hKey, /* handle to key to set value for */
593: value, /* name of the value to set */
594: 0, /* reserved */
595: REG_DWORD, /* flag for value type */
596: (BYTE*)&type, /* address of value data */
597: sizeof(type) /* size of value data */
598: );
599:
600: RegCloseKey(hKey);
601:
602: if(retval!=ERROR_SUCCESS) {
603: fprintf(stderr,"!Error %d setting registry key value (%s)\n"
604: ,retval,value);
605: return(FALSE);
606: }
607:
608: return(TRUE);
609: }
610:
611: static const char* start_type_desc(DWORD start_type)
612: {
613: static char str[128];
614:
615: switch(start_type) {
616: case SERVICE_AUTO_START: return("Startup: Automatic");
617: case SERVICE_DEMAND_START: return("Startup: Manual");
618: case SERVICE_DISABLED: return("Disabled");
619: case SERVICE_NOT_INSTALLED: return("Not installed");
620: }
621:
622: sprintf(str,"Start_type: %d", start_type);
623: return(str);
624: }
625:
626: static const char* state_desc(DWORD state)
627: {
628: static char str[128];
629:
630: switch(state) {
631: case SERVICE_STOPPED: return("Stopped");
632: case SERVICE_START_PENDING: return("Start Pending");
633: case SERVICE_STOP_PENDING: return("Stop Pending");
634: case SERVICE_RUNNING: return("Running");
635: case SERVICE_CONTINUE_PENDING: return("Continue Pending");
636: case SERVICE_PAUSE_PENDING: return("Pause Pending");
637: case SERVICE_PAUSED: return("Paused");
638: }
639:
640: sprintf(str,"State: %d", state);
641: return(str);
642: }
643:
644: static const char* control_desc(DWORD ctrl)
645: {
646: static char str[128];
647:
648: switch(ctrl) {
649: case SERVICE_CONTROL_STOP:
650: return("Stopping");
651: case SERVICE_CONTROL_PAUSE:
652: return("Pausing");
653: case SERVICE_CONTROL_CONTINUE:
654: return("Continuing");
655: case SERVICE_CONTROL_INTERROGATE:
656: return("Interrogating");
657: case SERVICE_CONTROL_SHUTDOWN:
658: return("Shutting-down");
659:
660: /* Synchronet-specific */
661: case SERVICE_CONTROL_RECYCLE:
662: return("Recycling");
663: case SERVICE_CONTROL_MUTE:
664: return("Muting");
665: case SERVICE_CONTROL_UNMUTE:
666: return("Un-muting");
667: case SERVICE_CONTROL_SYSOP_AVAILABLE:
668: return("Sysop Available");
669: case SERVICE_CONTROL_SYSOP_UNAVAILABLE:
670: return("Sysop Unavailable");
671: }
672: sprintf(str,"Control: %d", ctrl);
673: return(str);
674: }
675:
676: /****************************************************************************/
677: /* Utility function to detect if a service is currently disabled */
678: /****************************************************************************/
679: static DWORD get_service_info(SC_HANDLE hSCManager, char* name, DWORD* state)
680: {
681: SC_HANDLE hService;
682: DWORD size;
683: DWORD err;
684: SERVICE_STATUS status;
685: LPQUERY_SERVICE_CONFIG service_config;
686:
687: if(state!=NULL)
688: *state=SERVICE_STOPPED;
689:
690: if((hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS))==NULL) {
691: if((err=GetLastError())==ERROR_SERVICE_DOES_NOT_EXIST)
692: return(SERVICE_NOT_INSTALLED);
693: printf("\n!ERROR %d opening service: %s\n",err,name);
694: return(-1);
695: }
696:
697: if(QueryServiceConfig(
698: hService, /* handle of service */
699: NULL, /* address of service config. structure */
700: 0, /* size of service configuration buffer */
701: &size /* address of variable for bytes needed */
702: ) || GetLastError()!=ERROR_INSUFFICIENT_BUFFER) {
703: printf("\n!Unexpected QueryServiceConfig ERROR %u\n",err=GetLastError());
704: return(-1);
705: }
706:
707: if(state!=NULL && QueryServiceStatus(hService,&status))
708: *state=status.dwCurrentState;
709:
710: if((service_config=alloca(size))==NULL) {
711: printf("\n!ERROR allocating %u bytes of memory\n", size);
712: return(-1);
713: }
714:
715: if(!QueryServiceConfig(
716: hService, /* handle of service */
717: service_config, /* address of service config. structure */
718: size, /* size of service configuration buffer */
719: &size /* address of variable for bytes needed */
720: )) {
721: printf("\n!QueryServiceConfig ERROR %u\n",GetLastError());
722: return(-1);
723: }
724: CloseServiceHandle(hService);
725:
726: return(service_config->dwStartType);
727: }
728:
729: /****************************************************************************/
730: /* Utility function to create a service with description (on Win2K+) */
731: /****************************************************************************/
732: static SC_HANDLE create_service(HANDLE hSCMlib, SC_HANDLE hSCManager
733: ,char* name, char* display_name, char* description, char* path
734: ,BOOL autostart)
735: {
736: SC_HANDLE hService;
737: DWORD err;
738: DWORD start_type = autostart ? SERVICE_AUTO_START : SERVICE_DEMAND_START;
739:
740: printf("Installing service: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, display_name);
741:
742: hService = CreateService(
743: hSCManager, /* SCManager database */
744: name, /* name of service */
745: display_name, /* name to display */
746: SERVICE_ALL_ACCESS, /* desired access */
747: SERVICE_WIN32_SHARE_PROCESS, /* service type */
748: start_type, /* start type (auto or manual) */
749: SERVICE_ERROR_NORMAL, /* error control type */
750: path, /* service's binary */
751: NULL, /* no load ordering group */
752: NULL, /* no tag identifier */
753: "", /* dependencies */
754: NULL, /* LocalSystem account */
755: NULL); /* no password */
756:
757: if(hService==NULL) {
758: if((err=GetLastError())==ERROR_SERVICE_EXISTS)
759: printf("Already installed\n");
760: else
761: printf("!ERROR %d\n",err);
762: }
763: else {
764: describe_service(hSCMlib, hService,description);
765: CloseServiceHandle(hService);
766: printf("%s\n", start_type_desc(start_type));
767:
768: register_event_source(name,path);
769: register_event_source(NTSVC_NAME_EVENT,path); /* Create SynchronetEvent event source */
770: }
771:
772: return(hService);
773: }
774:
775: /****************************************************************************/
776: /* Install one or all services */
777: /****************************************************************************/
778: static int install(const char* svc_name)
779: {
780: int i;
781: HANDLE hSCMlib;
782: SC_HANDLE hSCManager;
783: char path[MAX_PATH+1];
784:
785: printf("Installing Synchronet NT Services...\n");
786:
787: hSCMlib = LoadLibrary("ADVAPI32.DLL");
788:
789: if(GetModuleFileName(NULL,path,sizeof(path))==0)
790: {
791: fprintf(stderr,"!ERROR %d getting module file name\n",GetLastError());
792: return(-1);
793: }
794:
795: hSCManager = OpenSCManager(
796: NULL, /* machine (NULL == local) */
797: NULL, /* database (NULL == default) */
798: SC_MANAGER_ALL_ACCESS /* access required */
799: );
800: if(hSCManager==NULL) {
801: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
802: return(-1);
803: }
804:
805: for(i=0;ntsvc_list[i]!=NULL;i++)
806: if(svc_name==NULL /* All? */
807: || !stricmp(ntsvc_list[i]->name, svc_name)
808: || !stricmp(ntsvc_list[i]->name+STRLEN_SYNCHRONET, svc_name))
809: create_service(hSCMlib
810: ,hSCManager
811: ,ntsvc_list[i]->name
812: ,ntsvc_list[i]->display_name
813: ,ntsvc_list[i]->description
814: ,path
815: ,ntsvc_list[i]->autostart);
816:
817: if(hSCMlib!=NULL)
818: FreeLibrary(hSCMlib);
819:
820: CloseServiceHandle(hSCManager);
821:
822: return(0);
823: }
824:
825: static SC_HANDLE open_service(SC_HANDLE hSCManager, char* name)
826: {
827: SC_HANDLE hService;
828: DWORD err;
829:
830: if((hService = OpenService(hSCManager, name, SERVICE_ALL_ACCESS))==NULL) {
831: if((err=GetLastError())==ERROR_SERVICE_DOES_NOT_EXIST)
832: printf("Not installed\n");
833: else
834: printf("\n!ERROR %d opening service: %s\n",err,name);
835: return(NULL);
836: }
837:
838: return(hService);
839: }
840:
841: /****************************************************************************/
842: /* Utility function to remove a service cleanly (stopping if necessary) */
843: /****************************************************************************/
844: static void remove_service(SC_HANDLE hSCManager, char* name, char* disp_name)
845: {
846: SC_HANDLE hService;
847: SERVICE_STATUS status;
848:
849: printf("Removing: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
850:
851: if((hService=open_service(hSCManager, name))==NULL)
852: return;
853:
854: /* try to stop the service */
855: if(ControlService( hService, SERVICE_CONTROL_STOP, &status))
856: {
857: printf("\nStopping: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
858:
859: while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING)
860: Sleep(1000);
861:
862: if(status.dwCurrentState == SERVICE_STOPPED)
863: printf("Stopped, ");
864: else
865: printf("FAILED!, ");
866: }
867:
868: /* now remove the service */
869: if(DeleteService(hService))
870: printf("Removed\n");
871: else
872: printf("!ERROR %d\n",GetLastError());
873: CloseServiceHandle(hService);
874: }
875:
876: /****************************************************************************/
877: /* Utility function to stop a service */
878: /****************************************************************************/
879: static void stop_service(SC_HANDLE hSCManager, char* name, char* disp_name)
880: {
881: SC_HANDLE hService;
882: SERVICE_STATUS status;
883:
884: printf("Stopping service: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
885: if((hService=open_service(hSCManager, name))==NULL)
886: return;
887:
888: /* try to stop the service */
889: if(ControlService( hService, SERVICE_CONTROL_STOP, &status))
890: {
891: while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_STOP_PENDING)
892: Sleep(1000);
893:
894: if(status.dwCurrentState == SERVICE_STOPPED)
895: printf("Stopped\n");
896: else
897: printf("FAILED!\n");
898: } else
899: printf("Already stopped\n");
900:
901: CloseServiceHandle(hService);
902: }
903:
904: /****************************************************************************/
905: /* Utility function to stop a service */
906: /****************************************************************************/
907: static void control_service(SC_HANDLE hSCManager, char* name, char* disp_name, DWORD ctrl)
908: {
909: SC_HANDLE hService;
910: SERVICE_STATUS status;
911: DWORD err;
912:
913: printf("%s service: %-*s ... ", control_desc(ctrl), STRLEN_MAX_DISPLAY_NAME, disp_name);
914: if((hService=open_service(hSCManager, name))==NULL)
915: return;
916:
917: /* try to stop the service */
918: if(!ControlService( hService, SERVICE_CONTROL_STOP, &status)) {
919: if((err=GetLastError())==ERROR_SERVICE_NOT_ACTIVE)
920: printf("Not active\n");
921: else
922: printf("!ERROR %d\n",err);
923: } else
924: printf("Successful\n");
925:
926: CloseServiceHandle(hService);
927: }
928:
929:
930:
931: /****************************************************************************/
932: /* Control one or all services */
933: /****************************************************************************/
934: static int control(const char* svc_name, DWORD ctrl)
935: {
936: int i;
937: SC_HANDLE hSCManager;
938:
939: hSCManager = OpenSCManager(
940: NULL, /* machine (NULL == local) */
941: NULL, /* database (NULL == default) */
942: SC_MANAGER_ALL_ACCESS /* access required */
943: );
944: if(hSCManager==NULL) {
945: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
946: return(-1);
947: }
948:
949: for(i=0;ntsvc_list[i]!=NULL;i++) {
950: #if 0
951: if(svc_name==NULL
952: && get_service_info(hSCManager, ntsvc_list[i]->name,NULL)==SERVICE_DISABLED)
953: continue;
954: #endif
955: if(svc_name==NULL /* All? */
956: || !stricmp(ntsvc_list[i]->name, svc_name)
957: || !stricmp(ntsvc_list[i]->name+STRLEN_SYNCHRONET, svc_name))
958: switch(ctrl) {
959: case SERVICE_CONTROL_STOP:
960: stop_service(hSCManager
961: ,ntsvc_list[i]->name
962: ,ntsvc_list[i]->display_name);
963: break;
964: default:
965: control_service(hSCManager
966: ,ntsvc_list[i]->name
967: ,ntsvc_list[i]->display_name
968: ,ctrl);
969: break;
970: }
971: }
972:
973: CloseServiceHandle(hSCManager);
974:
975: return(0);
976: }
977:
978: /****************************************************************************/
979: /* Utility function to start a service */
980: /****************************************************************************/
981: static void start_service(SC_HANDLE hSCManager, char* name, char* disp_name
982: ,int argc, char** argv)
983: {
984: SC_HANDLE hService;
985: SERVICE_STATUS status;
986:
987: printf("Starting service: %-*s ... ", STRLEN_MAX_DISPLAY_NAME, disp_name);
988: if((hService=open_service(hSCManager, name))==NULL)
989: return;
990:
991: if(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_RUNNING)
992: printf("Already running\n");
993: else {
994: /* Start the service */
995: if(StartService(hService, argc, (LPCTSTR*)argv))
996: {
997: while(QueryServiceStatus(hService, &status) && status.dwCurrentState == SERVICE_START_PENDING)
998: Sleep(1000);
999:
1000: if(status.dwCurrentState == SERVICE_RUNNING)
1001: printf("Started\n");
1002: else
1003: printf("FAILED!\n");
1004: } else
1005: printf("!ERROR %u\n", GetLastError());
1006: }
1007:
1008: CloseServiceHandle(hService);
1009: }
1010:
1011: /****************************************************************************/
1012: /* Uninstall one or all services */
1013: /****************************************************************************/
1014: static int uninstall(const char* svc_name)
1015: {
1016: int i;
1017: SC_HANDLE hSCManager;
1018:
1019: hSCManager = OpenSCManager(
1020: NULL, /* machine (NULL == local) */
1021: NULL, /* database (NULL == default) */
1022: SC_MANAGER_ALL_ACCESS /* access required */
1023: );
1024: if(hSCManager==NULL) {
1025: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
1026: return(-1);
1027: }
1028:
1029: for(i=0;ntsvc_list[i]!=NULL;i++)
1030: if(svc_name==NULL /* All? */
1031: || !stricmp(ntsvc_list[i]->name, svc_name)
1032: || !stricmp(ntsvc_list[i]->name+STRLEN_SYNCHRONET, svc_name))
1033: remove_service(hSCManager
1034: ,ntsvc_list[i]->name
1035: ,ntsvc_list[i]->display_name);
1036:
1037: CloseServiceHandle(hSCManager);
1038:
1039: return(0);
1040: }
1041:
1042: /****************************************************************************/
1043: /* Utility function to disable a service */
1044: /****************************************************************************/
1045: static void set_service_start_type(SC_HANDLE hSCManager, char* name
1046: ,char* disp_name, DWORD start_type)
1047: {
1048: SC_HANDLE hService;
1049:
1050: printf("%s service: %-*s ... "
1051: ,start_type==SERVICE_DISABLED ? "Disabling" : "Enabling"
1052: ,STRLEN_MAX_DISPLAY_NAME, disp_name);
1053:
1054: if((hService=open_service(hSCManager, name))==NULL)
1055: return;
1056:
1057: if(!ChangeServiceConfig(
1058: hService, /* handle to service */
1059: SERVICE_NO_CHANGE, /* type of service */
1060: start_type, /* when to start service */
1061: SERVICE_NO_CHANGE, /* severity if service fails to start */
1062: NULL, /* pointer to service binary file name */
1063: NULL, /* pointer to load ordering group name */
1064: NULL, /* pointer to variable to get tag identifier */
1065: NULL, /* pointer to array of dependency names */
1066: NULL, /* pointer to account name of service */
1067: NULL, /* pointer to password for service account */
1068: NULL /* pointer to display name */
1069: ))
1070: printf("\n!ERROR %d changing service config for: %s\n",GetLastError(),name);
1071: else
1072: printf("%s\n", start_type_desc(start_type));
1073:
1074: CloseServiceHandle(hService);
1075: }
1076:
1077: /****************************************************************************/
1078: /* Enable (set to auto-start) or disable one or all services */
1079: /****************************************************************************/
1080: static int enable(const char* svc_name, BOOL enabled)
1081: {
1082: int i;
1083: SC_HANDLE hSCManager;
1084:
1085: hSCManager = OpenSCManager(
1086: NULL, /* machine (NULL == local) */
1087: NULL, /* database (NULL == default) */
1088: SC_MANAGER_ALL_ACCESS /* access required */
1089: );
1090: if(hSCManager==NULL) {
1091: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
1092: return(-1);
1093: }
1094:
1095: for(i=0;ntsvc_list[i]!=NULL;i++)
1096: if(svc_name==NULL /* All? */
1097: || !stricmp(ntsvc_list[i]->name, svc_name)
1098: || !stricmp(ntsvc_list[i]->name+STRLEN_SYNCHRONET, svc_name))
1099: set_service_start_type(hSCManager
1100: ,ntsvc_list[i]->name
1101: ,ntsvc_list[i]->display_name
1102: ,enabled ? (ntsvc_list[i]->autostart ? SERVICE_AUTO_START : SERVICE_DEMAND_START)
1103: : SERVICE_DISABLED);
1104:
1105: CloseServiceHandle(hSCManager);
1106:
1107: return(0);
1108: }
1109:
1110: /****************************************************************************/
1111: /* List one or all services */
1112: /****************************************************************************/
1113: static int list(const char* svc_name)
1114: {
1115: int i;
1116: SC_HANDLE hSCManager;
1117: DWORD state;
1118: DWORD start_type;
1119:
1120: hSCManager = OpenSCManager(
1121: NULL, /* machine (NULL == local) */
1122: NULL, /* database (NULL == default) */
1123: SC_MANAGER_ALL_ACCESS /* access required */
1124: );
1125: if(hSCManager==NULL) {
1126: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
1127: return(-1);
1128: }
1129:
1130: for(i=0;ntsvc_list[i]!=NULL;i++) {
1131: if(svc_name==NULL
1132: || !stricmp(ntsvc_list[i]->name, svc_name)
1133: || !stricmp(ntsvc_list[i]->name+STRLEN_SYNCHRONET, svc_name)) {
1134: start_type = get_service_info(hSCManager, ntsvc_list[i]->name, &state);
1135: printf("%-*s ... %s, %s\n"
1136: ,STRLEN_MAX_DISPLAY_NAME, ntsvc_list[i]->display_name
1137: ,start_type_desc(start_type)
1138: ,state_desc(state));
1139: }
1140: }
1141:
1142: CloseServiceHandle(hSCManager);
1143:
1144: return(0);
1145: }
1146:
1147: /****************************************************************************/
1148: /* Start one or all services */
1149: /****************************************************************************/
1150: static int start(const char* svc_name, int argc, char** argv)
1151: {
1152: int i;
1153: SC_HANDLE hSCManager;
1154:
1155: hSCManager = OpenSCManager(
1156: NULL, /* machine (NULL == local) */
1157: NULL, /* database (NULL == default) */
1158: SC_MANAGER_ALL_ACCESS /* access required */
1159: );
1160: if(hSCManager==NULL) {
1161: fprintf(stderr,"!ERROR %d opening SC manager\n",GetLastError());
1162: return(-1);
1163: }
1164:
1165: for(i=0;ntsvc_list[i]!=NULL;i++) {
1166: if(svc_name==NULL
1167: && get_service_info(hSCManager, ntsvc_list[i]->name,NULL)==SERVICE_DISABLED)
1168: continue;
1169: if(svc_name==NULL
1170: || !stricmp(ntsvc_list[i]->name, svc_name)
1171: || !stricmp(ntsvc_list[i]->name+STRLEN_SYNCHRONET, svc_name))
1172: start_service(hSCManager,ntsvc_list[i]->name,ntsvc_list[i]->display_name
1173: ,argc,argv);
1174: }
1175:
1176: CloseServiceHandle(hSCManager);
1177:
1178: return(0);
1179: }
1180:
1181: /****************************************************************************/
1182: /* Main Entry Point */
1183: /****************************************************************************/
1184: int main(int argc, char** argv)
1185: {
1186: char* ctrl_dir;
1187: char* arg;
1188: char* p;
1189: char str[MAX_PATH+1];
1190: int i;
1191: FILE* fp=NULL;
1192: BOOL start_services=TRUE;
1193:
1194: SERVICE_TABLE_ENTRY ServiceDispatchTable[] =
1195: {
1196: { NTSVC_NAME_BBS, bbs_start },
1197: { NTSVC_NAME_FTP, ftp_start },
1198: { NTSVC_NAME_WEB, web_start },
1199: { NTSVC_NAME_MAIL, mail_start },
1200: { NTSVC_NAME_SERVICES, services_start },
1201: { NULL, NULL } /* Terminator */
1202: };
1203:
1204: printf("\nSynchronet NT Services Version %s%c %s\n\n"
1205: ,VERSION,REVISION,COPYRIGHT_NOTICE);
1206:
1207: ctrl_dir=getenv("SBBSCTRL"); /* read from environment variable */
1208: if(ctrl_dir==NULL || ctrl_dir[0]==0) {
1209: ctrl_dir="\\sbbs\\ctrl"; /* Not set? Use default */
1210: printf("!SBBSCTRL environment variable not set, using default value: %s\n\n"
1211: ,ctrl_dir);
1212: }
1213:
1214: sbbs_get_ini_fname(ini_file, ctrl_dir, NULL /* auto-host_name */);
1215:
1216: /* Initialize BBS startup structure */
1217: memset(&bbs_startup,0,sizeof(bbs_startup));
1218: bbs_startup.size=sizeof(bbs_startup);
1219: bbs_startup.cbdata=&bbs;
1220: bbs_startup.lputs=svc_lputs;
1221: bbs_startup.event_lputs=event_lputs;
1222: bbs_startup.started=svc_started;
1223: bbs_startup.recycle=svc_recycle;
1224: bbs_startup.terminated=svc_terminated;
1225: bbs_startup.clients=svc_clients;
1226: strcpy(bbs_startup.ctrl_dir,ctrl_dir);
1227:
1228: /* Initialize FTP startup structure */
1229: memset(&ftp_startup,0,sizeof(ftp_startup));
1230: ftp_startup.cbdata=&ftp;
1231: ftp_startup.size=sizeof(ftp_startup);
1232: ftp_startup.lputs=svc_lputs;
1233: ftp_startup.started=svc_started;
1234: ftp_startup.recycle=svc_recycle;
1235: ftp_startup.terminated=svc_terminated;
1236: ftp_startup.clients=svc_clients;
1237: strcpy(ftp_startup.ctrl_dir,ctrl_dir);
1238:
1239: /* Initialize Web Server startup structure */
1240: memset(&web_startup,0,sizeof(web_startup));
1241: web_startup.cbdata=&web;
1242: web_startup.size=sizeof(web_startup);
1243: web_startup.lputs=svc_lputs;
1244: web_startup.started=svc_started;
1245: web_startup.recycle=svc_recycle;
1246: web_startup.terminated=svc_terminated;
1247: web_startup.clients=svc_clients;
1248: strcpy(web_startup.ctrl_dir,ctrl_dir);
1249:
1250: /* Initialize Mail Server startup structure */
1251: memset(&mail_startup,0,sizeof(mail_startup));
1252: mail_startup.cbdata=&mail;
1253: mail_startup.size=sizeof(mail_startup);
1254: mail_startup.lputs=svc_lputs;
1255: mail_startup.started=svc_started;
1256: mail_startup.recycle=svc_recycle;
1257: mail_startup.terminated=svc_terminated;
1258: mail_startup.clients=svc_clients;
1259: strcpy(mail_startup.ctrl_dir,ctrl_dir);
1260:
1261: /* Initialize Services startup structure */
1262: memset(&services_startup,0,sizeof(services_startup));
1263: services_startup.cbdata=&services;
1264: services_startup.size=sizeof(services_startup);
1265: services_startup.lputs=svc_lputs;
1266: services_startup.started=svc_started;
1267: services_startup.recycle=svc_recycle;
1268: services_startup.terminated=svc_terminated;
1269: services_startup.clients=svc_clients;
1270: strcpy(services_startup.ctrl_dir,ctrl_dir);
1271:
1272: /* Read .ini file here */
1273: if((fp=fopen(ini_file,"r"))!=NULL) {
1274: sprintf(str,"Reading %s",ini_file);
1275: svc_lputs(NULL,LOG_INFO,str);
1276: }
1277:
1278: /* We call this function to set defaults, even if there's no .ini file */
1279: sbbs_read_ini(fp
1280: ,NULL /* global_startup */
1281: ,&bbs.autostart ,NULL
1282: ,&ftp.autostart ,NULL
1283: ,&web.autostart ,NULL
1284: ,&mail.autostart ,NULL
1285: ,&services.autostart ,NULL
1286: );
1287:
1288: /* close .ini file here */
1289: if(fp!=NULL)
1290: fclose(fp);
1291:
1292: if(chdir(ctrl_dir)!=0) {
1293: sprintf(str,"!ERROR %d changing directory to: %s", errno, ctrl_dir);
1294: svc_lputs(NULL,LOG_ERR,str);
1295: }
1296:
1297: for(i=1;i<argc;i++) {
1298: arg=argv[i];
1299: while(*arg=='-' || *arg=='/')
1300: arg++;
1301: if(!stricmp(arg,"help") || *arg=='?')
1302: start_services=FALSE;
1303:
1304: if(!stricmp(arg,"list"))
1305: return list(argv[i+1]);
1306:
1307: if(!stricmp(arg,"install"))
1308: return install(argv[i+1]);
1309:
1310: if(!stricmp(arg,"remove"))
1311: return uninstall(argv[i+1]);
1312:
1313: if(!stricmp(arg,"disable"))
1314: return enable(argv[i+1], FALSE);
1315:
1316: if(!stricmp(arg,"enable"))
1317: return enable(argv[i+1], TRUE);
1318:
1319: if(!stricmp(arg,"stop"))
1320: return control(argv[i+1],SERVICE_CONTROL_STOP);
1321:
1322: if(!stricmp(arg,"start"))
1323: return start(argv[i+1],argc,argv);
1324:
1325: if(!stricmp(arg,"recycle"))
1326: return control(argv[i+1],SERVICE_CONTROL_RECYCLE);
1327:
1328: if(!stricmp(arg,"mute"))
1329: return control(argv[i+1],SERVICE_CONTROL_MUTE);
1330:
1331: if(!stricmp(arg,"unmute"))
1332: return control(argv[i+1],SERVICE_CONTROL_UNMUTE);
1333: }
1334:
1335: if(start_services) {
1336: printf("Starting service control dispatcher.\n" );
1337: printf("This may take several seconds. Please wait.\n" );
1338:
1339: if(StartServiceCtrlDispatcher(ServiceDispatchTable))
1340: return(0);
1341:
1342: sprintf(str,"!ERROR %u starting service control dispatcher",GetLastError());
1343: printf("%s\n\n",str);
1344: OutputDebugString(str);
1345: }
1346:
1347: SAFECOPY(str,getfname(argv[0]));
1348: if((p=getfext(str))!=NULL)
1349: *p=0;
1350:
1351: printf("Usage: %s [command] [service]\n", str);
1352:
1353: printf("\nIf service name not specified, default is ALL services.\n");
1354:
1355: printf("\nAvailable Commands:\n\n");
1356: printf("%-20s %s\n","list","to list services");
1357: printf("%-20s %s\n","install","to install services");
1358: printf("%-20s %s\n","remove","to remove serivces");
1359: printf("%-20s %s\n","disable","to disable services");
1360: printf("%-20s %s\n","enable","to re-enable disabled services");
1361: printf("%-20s %s\n","start","to start services");
1362: printf("%-20s %s\n","stop","to stop services");
1363: printf("%-20s %s\n","recycle","to recycle services");
1364: printf("%-20s %s\n","mute","to mute (sounds of) services");
1365: printf("%-20s %s\n","unmute","to unmute (sounds of) services");
1366:
1367: printf("\nAvailable Services:\n\n");
1368: printf("%-20s %s\n","Name","Description");
1369: printf("%-20s %s\n","----","-----------");
1370: for(i=0;ntsvc_list[i]!=NULL;i++)
1371: printf("%-20s %s\n",ntsvc_list[i]->name+STRLEN_SYNCHRONET,ntsvc_list[i]->display_name);
1372:
1373: return(0);
1374: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.