1 /* vi:ai:et:ts=8 sw=2
2 */
3 /*
4 * wzdftpd - a modular and cool ftp server
5 * Copyright (C) 2002-2004 Pierre Chifflier
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * As a special exemption, Pierre Chifflier
22 * and other respective copyright holders give permission to link this program
23 * with OpenSSL, and distribute the resulting executable, without including
24 * the source code for OpenSSL in the source distribution.
25 */
26 /** \file wzd_main.c
27 * \brief Startup code: check args, load config file and start main thread.
28 */
29 /*! \addtogroup wzdftpd
30 * \brief Main executable group
31 * @{
32 */
33
34 /* Sanity check */
35 #ifdef WZD_MULTIPROCESS
36 #ifdef WZD_MULTITHREAD
37
38 #error "You CAN'T have a multi-thread multi-process server, stupid !"
39
40 #endif /* WZD_MULTITHREAD */
41 #endif /* WZD_MULTIPROCESS */
42
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <time.h>
50
51 #ifdef WIN32
52 #include <winsock2.h>
53
54 #include "../visual/gnu_regex/regex.h"
55
56 #include <Windows.h>
57 #else
58 #include <unistd.h>
59
60 #include <sys/types.h>
61 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
64
65 #include <regex.h>
66
67 #include <syslog.h>
68
69 #if defined(__sun__)
70 # define LOG_FTP LOG_DAEMON
71 #endif
72
73 #endif
74
75 #include <errno.h>
76 #include <fcntl.h>
77
78 #include <libwzd-core/wzd_structs.h>
79
80 #include <libwzd-core/wzd_misc.h>
81 #include <libwzd-core/wzd_log.h>
82 #include <libwzd-core/wzd_messages.h>
83 #include <libwzd-core/wzd_tls.h>
84 #include <libwzd-core/wzd_configfile.h>
85 #include <libwzd-core/wzd_configloader.h>
86 #include <libwzd-core/wzd_libmain.h>
87 #include <libwzd-core/wzd_utf8.h>
88
89 #include "wzd_opts.h"
90 #include "wzd_ServerThread.h"
91
92 #include <libwzd-core/wzd_debug.h>
93
94 #include "wzd_version.h"
95
96 #ifdef WIN32
97 int nt_service_register(void);
98 int nt_service_unregister(void);
99 int nt_service_start(void);
100 int nt_service_stop(void);
101 int nt_is_service(void);
102
103 VOID UpdateSCM( DWORD dwCurrentState , DWORD dwWaitHint , DWORD dwWin32ExitCode );
104 VOID MyServiceRun(DWORD argc, LPSTR *argv);
105 VOID MyServiceCtrlHandler(DWORD opcode);
106
107 void SvcDebugOut(const char *fmt,...);
108
109 SERVICE_STATUS service_status;
110 SERVICE_STATUS_HANDLE service_status_handle;
111
112 static int ntservice=0;
113 #endif
114
115 typedef enum {
116 CMD_NONE=0,
117 #ifdef WIN32
118 CMD_SRV_REGISTER,
119 CMD_SRV_UNREGISTER,
120 CMD_SRV_START,
121 CMD_SRV_STOP,
122 #endif
123 CMD_TEST_CONFIG,
124 } wzd_arg_command_t;
125
126 char configfile_name[256];
127 int stay_foreground=0;
128 static wzd_arg_command_t start_command=CMD_NONE;
129
130 static const char * config_files[] = {
131 "",
132 WZD_DEFAULT_CONF,
133 "wzd.cfg",
134 "/etc/wzdftpd/wzd.cfg",
135 "/etc/wzd.cfg",
136 "/usr/local/etc/wzd.cfg",
137 NULL /* do NOT remove */
138 };
139
display_usage(void)140 void display_usage(void)
141 {
142 fprintf(stderr,"%s build %s (%s)\n", WZD_VERSION_LONG,WZD_BUILD_NUM,WZD_BUILD_OPTS);
143 fprintf(stderr, "\nusage: wzdftpd [arguments]\n");
144 fprintf(stderr,"\narguments:\r\n");
145 #ifdef HAVE_GETOPT_LONG
146 fprintf(stderr," -h, --help - Display this text \n");
147 #if DEBUG
148 fprintf(stderr," -b, --background - Force background \n");
149 #endif
150 fprintf(stderr," -f <file> - Load alternative config file \n");
151 fprintf(stderr," -s, --force-foreground - Stay in foreground \n");
152 fprintf(stderr," -t, --configtest - Test configuration file\n");
153 fprintf(stderr," -V, --version - Show version \n");
154 #else /* HAVE_GETOPT_LONG */
155 fprintf(stderr," -h - Display this text \n");
156 #if DEBUG
157 fprintf(stderr," -b - Force background \n");
158 #endif
159 fprintf(stderr," -f <file> - Load alternative config file \n");
160 fprintf(stderr," -s - Stay in foreground \n");
161 #ifdef WIN32
162 fprintf(stderr," -si - Register service \n");
163 fprintf(stderr," -sd - Unregister service \n");
164 fprintf(stderr," -ss - Start service (must be registered) \n");
165 fprintf(stderr," -st - Stop service (must be registered) \n");
166 #endif
167 fprintf(stderr," -V - Show version \n");
168
169 #endif /* HAVE_GETOPT_LONG */
170 }
171
172
main_parse_args(int argc,char ** argv)173 int main_parse_args(int argc, char **argv)
174 {
175 #ifndef WIN32
176 int opt;
177
178
179 #ifdef HAVE_GETOPT_LONG
180 static struct option long_options[] =
181 {
182 /* Options without arguments: */
183 { "background", no_argument, NULL, 'b' },
184 { "config-file", required_argument, NULL, 'f' },
185 { "help", no_argument, NULL, 'h' },
186 { "force-foreground", no_argument, NULL, 's' },
187 { "configtest", no_argument, NULL, 't' },
188 { "version", no_argument, NULL, 'V' },
189 { NULL, 0, NULL, 0 } /* sentinel */
190 };
191
192 /* please keep options ordered ! */
193 /* while ((opt=getopt(argc, argv, "hbdf:sV")) != -1) {*/
194 while ((opt=getopt_long(argc, argv, "hbf:stV", long_options, (int *)0)) != -1)
195 #else /* HAVE_GETOPT_LONG */
196 while ((opt=getopt(argc, argv, "hbf:stV")) != -1)
197 #endif /* HAVE_GETOPT_LONG */
198 {
199 switch((char)opt) {
200 case 'b':
201 stay_foreground = 0;
202 break;
203 case 'f':
204 if (strlen(optarg)>=255) {
205 fprintf(stderr,"filename too long (>255 chars)\n");
206 return 1;
207 }
208 strncpy(configfile_name,optarg,255);
209 break;
210 case 'h':
211 display_usage();
212 exit (0);
213 case 's':
214 stay_foreground = 1;
215 break;
216 case 't':
217 start_command = CMD_TEST_CONFIG;
218 break;
219 case 'V':
220 fprintf(stderr,"%s build %s (%s)\n",
221 WZD_VERSION_LONG,WZD_BUILD_NUM,WZD_BUILD_OPTS);
222 exit (0);
223 }
224 }
225 #else /* WIN32 */
226 if (argc > 1) {
227 int optindex=1;
228 while (optindex < argc) {
229 if (!strcmp(argv[optindex],"-f")) {
230 optindex++;
231 if (optindex < argc) {
232 if (strlen(argv[optindex])>=255) {
233 fprintf(stderr,"filename too long (>255 chars)\n");
234 return 1;
235 }
236 strncpy(configfile_name,argv[optindex],255);
237 optindex++;
238 } else {
239 fprintf(stderr,"missing filename after -f option\n");
240 return 1;
241 }
242 continue;
243 }
244 if (!strcmp(argv[optindex],"-b")) {
245 stay_foreground = 0;
246 optindex++;
247 continue;
248 }
249 if (!strcmp(argv[optindex],"-s")) {
250 stay_foreground = 1;
251 optindex++;
252 continue;
253 }
254 if (!strcmp(argv[optindex],"-h") || !strcmp(argv[optindex],"--help")
255 || !strcmp(argv[optindex],"/?") || !strcmp(argv[optindex],"-?")) {
256 display_usage();
257 exit (0);
258 }
259 if (!strcmp(argv[optindex],"-V")) {
260 fprintf(stderr,"%s build %s (%s)\n",
261 WZD_VERSION_LONG,WZD_BUILD_NUM,WZD_BUILD_OPTS);
262 exit (0);
263 }
264 if (!strcmp(argv[optindex],"-si")) {
265 start_command = CMD_SRV_REGISTER;
266 optindex++;
267 continue;
268 }
269 if (!strcmp(argv[optindex],"-sd")) {
270 start_command = CMD_SRV_UNREGISTER;
271 optindex++;
272 continue;
273 }
274 if (!strcmp(argv[optindex],"-ss")) {
275 start_command = CMD_SRV_START;
276 optindex++;
277 continue;
278 }
279 if (!strcmp(argv[optindex],"-st")) {
280 start_command = CMD_SRV_STOP;
281 optindex++;
282 continue;
283 }
284 if (!strcmp(argv[optindex],"-t")) {
285 start_command = CMD_TEST_CONFIG;
286 optindex++;
287 continue;
288 }
289 if (!strcmp(argv[optindex],"-service")) {
290 ntservice = 1;
291 optindex++;
292 continue;
293 }
294 break;
295 }
296 }
297 #endif /* WIN32 */
298 return 0;
299 }
300
301
302
main(int argc,char ** argv)303 int main(int argc, char **argv)
304 {
305 int ret, i;
306 pid_t forkresult;
307 wzd_config_t * config;
308 wzd_configfile_t * cf;
309
310 /* register wzdftpd mutex so the installer/other programs can check if wzdftpd is active */
311 #ifdef WIN32
312 CreateMutex(NULL,FALSE,"wzdftpdIsActive");
313 CreateMutex(NULL,FALSE,"Global\\wzdftpdIsActive");
314 #endif
315
316 wzd_debug_init();
317
318
319 #if 0
320 fprintf(stderr,"--------------------------------------\n");
321 fprintf(stderr,"\n");
322 fprintf(stderr,"This is a beta release, in active development\n");
323 fprintf(stderr,"Things may break from version to version\n");
324 fprintf(stderr,"Want stability ? Use a 0.4 version. YOU WERE WARNED!\n");
325 fprintf(stderr,"\n");
326 fprintf(stderr,"--------------------------------------\n");
327 fprintf(stderr,"\n");
328 #endif
329
330 #if DEBUG
331 stay_foreground = 1;
332 #endif
333 /* default value */
334 /* strcpy(configfile_name,"wzd.cfg");*/
335 configfile_name[0]='\0';
336
337 if (argc > 1) {
338 ret = main_parse_args(argc,argv);
339 if (ret) {
340 out_err(LEVEL_CRITICAL,"Error while parsing args, aborting\n");
341 return 0;
342 }
343 config_files[0] = configfile_name;
344
345 switch (start_command) {
346 #ifdef WIN32
347 case CMD_SRV_UNREGISTER:
348 nt_service_unregister();
349 exit (0);
350 case CMD_SRV_START:
351 nt_service_start();
352 exit (0);
353 case CMD_SRV_STOP:
354 nt_service_stop();
355 exit (0);
356 #endif
357 case CMD_TEST_CONFIG:
358 {
359 const char * test_config = NULL;
360 /* try new config file format first */
361 cf = config_new();
362 for (i=0; config_files[i]; i++) {
363 if (config_files[i][0]!='\0') { test_config = config_files[i]; break; }
364 }
365 if (test_config == NULL) {
366 out_err(LEVEL_CRITICAL,"Could not find ANY config file !\n");
367 out_err(LEVEL_CRITICAL,"Try restarting with command -f <config>\n");
368 exit (1);
369 }
370 out_err(LEVEL_NORMAL,"Testing configuration file %s\n",test_config);
371 ret = config_load_from_file (cf, test_config, 0);
372 if (!ret) {
373 int err;
374
375 out_err(LEVEL_INFO,"config: NEW format found [%s]\n",config_files[i]);
376
377 config = cfg_store(cf,&err);
378 if (config) {
379 out_err(LEVEL_NORMAL,"*** Configuration test OK ***\n");
380 exit (0);
381 }
382 }
383 out_err(LEVEL_CRITICAL,"ERROR: could NOT load config file %s\n",test_config);
384 config_free(cf);
385 }
386 exit (-1);
387 default:
388 break;
389 }
390 }
391
392 if (!stay_foreground) {
393 #ifndef WIN32
394 forkresult = fork();
395 #else
396 forkresult = 0;
397 #endif
398
399 if ((int)forkresult == -1)
400 fprintf(stderr,"Could not fork into background\n");
401 if ((int)forkresult != 0)
402 exit(0);
403 }
404
405 /* initialize random seed */
406 srand((unsigned int)(time(NULL)+0x13313043));
407
408 /* not really usefull, but will also initialize var if not used :) */
409 #ifndef WIN32
410 setlib_server_uid(geteuid());
411 #endif
412
413 /* initialize logging facilities */
414 if (log_init()) {
415 fprintf(stderr,"FATAL: Couldn't init logging facilities, aborting\n");
416 exit(1);
417 }
418
419 /* default server messages */
420 init_default_messages();
421
422 /* config file */
423 config = NULL;
424
425 for (i=0; config_files[i]; i++)
426 {
427 /* try new config file format first */
428 cf = config_new();
429 ret = config_load_from_file (cf, config_files[i], 0);
430 if (!ret) {
431 int err;
432
433 out_err(LEVEL_INFO,"config: NEW format found [%s]\n",config_files[i]);
434
435 config = cfg_store(cf,&err);
436 if (config) {
437 /* cf will NOT be freed at this point, it is stored into config */
438 break;
439 }
440 }
441 config_free(cf);
442 if (!ret) break;
443 }
444
445 if (!config) {
446 fprintf(stderr,"FATAL: No valid config file found, aborting!\n");
447 out_err(LEVEL_CRITICAL,"FATAL: Critical error loading config file, aborting\n");
448 exit(1);
449 }
450
451 config->config_filename = wzd_strdup(config_files[i]);
452
453
454 /* \todo XXX use values given in command-line ? */
455 switch (start_command) {
456 case CMD_NONE:
457 break;
458 #ifdef WIN32
459 case CMD_SRV_REGISTER:
460 mainConfig = config;
461 nt_service_register();
462 exit (0);
463 case CMD_SRV_UNREGISTER:
464 mainConfig = config;
465 nt_service_unregister();
466 exit (0);
467 case CMD_SRV_START:
468 mainConfig = config;
469 nt_service_start();
470 exit (0);
471 case CMD_SRV_STOP:
472 mainConfig = config;
473 nt_service_stop();
474 exit (0);
475 #endif
476 default:
477 break;
478 }
479
480
481 mainConfig = config;
482 setlib_mainConfig(mainConfig);
483
484 #ifndef WIN32
485 if (CFG_GET_OPTION(mainConfig,CFG_OPT_USE_SYSLOG)) {
486 openlog("wzdftpd", LOG_CONS | LOG_NDELAY | LOG_PID, LOG_FTP);
487 // LOG_CONS - If syslog could not pass our messages they'll apear on console,
488 // LOG_NDELAY - We don't want to wait for first message but open the connection to syslogd immediatly
489 // LOG_PID - We want see pid of of deamon in logfiles (Is it needed?)
490 for (i=0; i<MAX_LOG_CHANNELS; i++)
491 log_set_syslog(i,1);
492 }
493 #endif
494 if (mainConfig->logfilename != NULL) {
495 ret = log_open(mainConfig->logfilename,mainConfig->logfilemode);
496 if (ret < 0) {
497 /* stderr is not closed here, even in release mode */
498 fprintf(stderr,"FATAL: Could not open log file %s\n",mainConfig->logfilename);
499 return 1;
500 }
501 /** \todo this should be removed (as well as log_get() function) and replace
502 * with a proper init code
503 */
504 for (i=0; i<MAX_LOG_CHANNELS; i++) {
505 if (log_get(i) == -1)
506 log_set(i,ret);
507 }
508 }
509
510 #if defined(HAVE_OPENSSL) || defined(HAVE_GNUTLS)
511 ret = tls_init();
512 if (ret) {
513 out_log(LEVEL_CRITICAL,"TLS subsystem could not be initialized.\n");
514 return 1;
515 }
516 #endif
517
518 utf8_detect(mainConfig);
519
520 #if defined(DEBUG) || !defined(WIN32)
521 ret = runMainThread(argc,argv);
522 #else
523 if (ntservice)
524 {
525 SERVICE_TABLE_ENTRY DispatchTable[] = {
526 { "wzdftpd", (LPSERVICE_MAIN_FUNCTION)MyServiceRun },
527 { NULL, NULL }
528 };
529 if (!StartServiceCtrlDispatcher(DispatchTable))
530 SvcDebugOut( "[wzdftpd] StartServiceCtrlDispatcher error = %d\n", GetLastError());
531 }
532 else
533 ret = runMainThread(argc,argv);
534 #endif
535
536 /* we should never pass here - see wzd_ServerThread.c */
537
538 return ret;
539 }
540
541 #ifdef WIN32
542
543 /** \brief Report the status to the service manager */
UpdateSCM(DWORD dwCurrentState,DWORD dwWaitHint,DWORD dwWin32ExitCode)544 VOID UpdateSCM(DWORD dwCurrentState, DWORD dwWaitHint, DWORD dwWin32ExitCode)
545 {
546 DWORD status;
547
548 service_status.dwServiceType = SERVICE_WIN32;
549 service_status.dwCurrentState = dwCurrentState;
550 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
551 service_status.dwWin32ExitCode = dwWin32ExitCode;
552 service_status.dwServiceSpecificExitCode = 0;
553 service_status.dwCheckPoint = 0;
554 service_status.dwWaitHint = dwWaitHint;
555
556 /* report status */
557 if (!SetServiceStatus(service_status_handle, &service_status)){
558 status = GetLastError();
559 SvcDebugOut(" [wzdftpd] SetServiceStatus %d error %d\n",dwCurrentState,GetLastError() );
560 }
561 }
562
MyServiceRun(DWORD argc,LPSTR * argv)563 VOID MyServiceRun(DWORD argc, LPSTR *argv)
564 {
565 int ret;
566
567 service_status_handle = RegisterServiceCtrlHandler( "wzdftpd", (LPHANDLER_FUNCTION)MyServiceCtrlHandler);
568 if (!service_status_handle){
569 SvcDebugOut( "[wzdftpd] RegisterServiceCtrlHandler error = %d\n", GetLastError() );
570 return;
571 }
572
573 /* report start pending status */
574 UpdateSCM( SERVICE_START_PENDING , 0 , 0 );
575
576 /* Actually there should pass some time/stuff between reporting the pending and running status */
577 UpdateSCM( SERVICE_RUNNING , 0 , 0 );
578 /* This is where the service does its work */
579 SvcDebugOut("[wzdftpd] Going to run main thread\n");
580 ret = runMainThread(argc,argv);
581
582 SvcDebugOut("[wzdftpd] Reported SERVICE_STOPPED\n");
583 /* report stopped status */
584 UpdateSCM( SERVICE_STOPPED , 0, 0 );
585 }
586
MyServiceCtrlHandler(DWORD opcode)587 VOID MyServiceCtrlHandler(DWORD opcode)
588 {
589 DWORD status;
590
591 switch(opcode)
592 {
593 case SERVICE_CONTROL_PAUSE:
594 break;
595 case SERVICE_CONTROL_CONTINUE:
596 break;
597 case SERVICE_CONTROL_STOP:
598 mainConfig->serverstop = 1;
599 UpdateSCM( SERVICE_STOP_PENDING , 5000 , 0 );
600 SvcDebugOut(" [wzdftpd] exiting\n",0);
601 return;
602 case SERVICE_CONTROL_INTERROGATE:
603 /* fall through to send current status */
604 break;
605 default:
606 SvcDebugOut(" [wzdftpd] Unrecognized opcode %ld\n",opcode);
607 break;
608 }
609
610 /* send current status */
611 if (!SetServiceStatus(service_status_handle,&service_status)) {
612 status = GetLastError();
613 SvcDebugOut(" [wzdftpd] SetServiceStatus error %ld\n",status);
614 }
615 }
616
nt_service_register(void)617 int nt_service_register(void)
618 {
619 SC_HANDLE schService, schSCManager;
620 LPCTSTR binaryPathName;
621 char buffer[MAX_PATH+1];
622 char config_fullpath[MAX_PATH+1];
623 char startcmd[MAX_PATH+1];
624
625 if ( !mainConfig || !mainConfig->config_filename ||
626 !_fullpath(config_fullpath,mainConfig->config_filename,MAX_PATH) ) {
627 fprintf(stderr,"fullpath failed %d\n",GetLastError());
628 return -1;
629 }
630
631 /* obtain a handler to the SC Manager database */
632 schSCManager = OpenSCManager(
633 NULL, /* local machine */
634 NULL, /* ServicesActive database */
635 SC_MANAGER_ALL_ACCESS); /* full access rights */
636
637 if (schSCManager == NULL) return -1;
638
639 GetModuleFileName(NULL,buffer,sizeof(buffer));
640 binaryPathName = buffer;
641
642 snprintf(startcmd,MAX_PATH,"%s -f \"%s\" -service",binaryPathName,config_fullpath);
643
644 schService = CreateService(
645 schSCManager, /* SCManager database */
646 "wzdftpd", /* name of service */
647 "wzdftpd", /* service name to display */
648 SERVICE_ALL_ACCESS, /* desired access */
649 SERVICE_WIN32_OWN_PROCESS,/* service type */
650 SERVICE_DEMAND_START, /* start type */
651 SERVICE_ERROR_NORMAL, /* error control type */
652 startcmd, /* service's binary */
653 NULL, /* no load ordering group */
654 NULL, /* no tag identifier */
655 NULL, /* no dependancies */
656 NULL, /* LocalSystem account */
657 NULL); /* no password */
658
659 if (schService == NULL) {
660 fprintf(stderr,"CreateService failed %d\n",GetLastError());
661 CloseServiceHandle(schSCManager);
662 return -1;
663 }
664
665 CloseServiceHandle(schService);
666 CloseServiceHandle(schSCManager);
667
668 return 0;
669 }
670
nt_service_unregister(void)671 int nt_service_unregister(void)
672 {
673 SC_HANDLE schService, schSCManager;
674
675 /* obtain a handler to the SC Manager database */
676 schSCManager = OpenSCManager(
677 NULL, /* local machine */
678 NULL, /* ServicesActive database */
679 SC_MANAGER_ALL_ACCESS); /* full access rights */
680
681 if (schSCManager == NULL) return -1;
682
683 schService = OpenService(
684 schSCManager, /* SCManager database */
685 "wzdftpd", /* name of service */
686 DELETE); /* only need DELETE access */
687
688 if (schService == NULL) {
689 fprintf(stderr,"OpenService failed %d\n",GetLastError());
690 CloseServiceHandle(schSCManager);
691 return -1;
692 }
693
694 if (!DeleteService(schService)) {
695 fprintf(stderr,"DeleteService failed %d\n",GetLastError());
696 CloseServiceHandle(schSCManager);
697 return -1;
698 }
699
700 CloseServiceHandle(schService);
701 CloseServiceHandle(schSCManager);
702
703 return 0;
704 }
705
nt_service_start(void)706 int nt_service_start(void)
707 {
708 SC_HANDLE schService, schSCManager;
709 SERVICE_STATUS ssStatus;
710 DWORD dwOldCheckPoint;
711 DWORD dwStartTickCount;
712 DWORD dwWaitTime;
713
714 /* obtain a handler to the SC Manager database */
715 schSCManager = OpenSCManager(
716 NULL, /* local machine */
717 NULL, /* ServicesActive database */
718 SC_MANAGER_ALL_ACCESS); /* full access rights */
719
720 if (schSCManager == NULL) return -1;
721
722 schService = OpenService(
723 schSCManager, /* SCManager database */
724 "wzdftpd", /* name of service */
725 SERVICE_ALL_ACCESS);
726
727 if (schService == NULL) {
728 fprintf(stderr,"OpenService failed %d\n",GetLastError());
729 CloseServiceHandle(schSCManager);
730 return -1;
731 }
732
733 if (!StartService(
734 schService, /* handle to service */
735 0, /* number of arguments */
736 NULL)) /* no arguments */
737 {
738 fprintf(stderr,"Service started\n");
739 CloseServiceHandle(schService);
740 CloseServiceHandle(schSCManager);
741 return 0;
742 } else {
743 fprintf(stderr,"Service start pending\n");
744
745 /* check the status until the service is no longer start pending */
746 if (!QueryServiceStatus(
747 schService, /* handle to service */
748 &ssStatus)) /* address of status information structure */
749 {
750 CloseServiceHandle(schSCManager);
751 return -1;
752 }
753
754 /* save the tick count and initial checkpoint */
755 dwStartTickCount = GetTickCount();
756 dwOldCheckPoint = ssStatus.dwCheckPoint;
757
758 while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
759 {
760 /* do not wait longer than the wait hint. A good interval is
761 * one tenth the wait hint, but no less than 1 second and no
762 * more than 10 seconds
763 */
764 dwWaitTime = ssStatus.dwWaitHint / 10;
765 if (dwWaitTime < 1000)
766 dwWaitTime = 1000;
767 else if (dwWaitTime > 10000)
768 dwWaitTime = 10000;
769
770 Sleep(dwWaitTime);
771
772 /* check the status again */
773 if (!QueryServiceStatus(
774 schService, /* handle to service */
775 &ssStatus)) /* address of status information structure */
776 break;
777
778 fprintf(stderr,".");
779 fflush(stderr);
780
781 if (ssStatus.dwCheckPoint > dwOldCheckPoint)
782 {
783 /* the service is making progress */
784 dwStartTickCount = GetTickCount();
785 dwOldCheckPoint = ssStatus.dwCheckPoint;
786 } else {
787 if (GetTickCount()-dwStartTickCount > ssStatus.dwWaitHint)
788 {
789 /* no progress made withiin the wait hint */
790 break;
791 }
792 }
793 }
794
795 }
796
797 CloseServiceHandle(schService);
798 CloseServiceHandle(schSCManager);
799
800 if (ssStatus.dwCurrentState == SERVICE_RUNNING)
801 {
802 fprintf(stderr,"Service started.\n");
803 } else {
804 fprintf(stderr,"Service not started\n");
805 }
806
807 return 0;
808 }
809
nt_service_stop(void)810 int nt_service_stop(void)
811 {
812 SC_HANDLE schService, schSCManager;
813 SERVICE_STATUS ssStatus;
814 DWORD dwStartTime;
815 DWORD dwTimeout;
816
817 /* obtain a handler to the SC Manager database */
818 schSCManager = OpenSCManager(
819 NULL, /* local machine */
820 NULL, /* ServicesActive database */
821 SC_MANAGER_ALL_ACCESS); /* full access rights */
822
823 if (schSCManager == NULL) return -1;
824
825 schService = OpenService(
826 schSCManager, /* SCManager database */
827 "wzdftpd", /* name of service */
828 SERVICE_ALL_ACCESS);
829
830 if (schService == NULL) {
831 fprintf(stderr,"OpenService failed %d\n",GetLastError());
832 CloseServiceHandle(schSCManager);
833 return -1;
834 }
835 dwStartTime = GetTickCount();
836 dwTimeout = 10000; /* 10s */
837
838 if (!QueryServiceStatus( schService, &ssStatus))
839 return GetLastError();
840
841 if (ssStatus.dwCurrentState == SERVICE_STOPPED) {
842 fprintf(stderr,"Service already stopped\n");
843 return 0;
844 }
845
846 /* if a stop is pending, just wait for it */
847 while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
848 {
849 Sleep(ssStatus.dwWaitHint);
850
851 if (!QueryServiceStatus( schService, &ssStatus))
852 return GetLastError();
853
854 if (GetTickCount()-dwStartTime > dwTimeout) {
855 fprintf(stderr,"Timeout\n");
856 return -1;
857 }
858 }
859
860 if (!ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus))
861 return GetLastError();
862
863 /* wait for the service to stop */
864 while (ssStatus.dwCurrentState != SERVICE_STOPPED)
865 {
866 Sleep(ssStatus.dwWaitHint);
867
868 if (!QueryServiceStatus( schService, &ssStatus))
869 return GetLastError();
870
871 if (GetTickCount()-dwStartTime > dwTimeout) {
872 fprintf(stderr,"Timeout\n");
873 return -1;
874 }
875 }
876
877 CloseServiceHandle(schService);
878 CloseServiceHandle(schSCManager);
879
880 if (ssStatus.dwCurrentState == SERVICE_STOPPED)
881 {
882 fprintf(stderr,"Service stopped.\n");
883 } else {
884 fprintf(stderr,"Service not stopped\n");
885 }
886
887 return 0;
888 }
889
SvcDebugOut(const char * fmt,...)890 void SvcDebugOut(const char *fmt,...)
891 {
892 va_list argptr;
893 char buffer[4096];
894
895 va_start(argptr,fmt);
896 vsnprintf(buffer,1024,fmt,argptr);
897 va_end(argptr);
898
899 OutputDebugStringA(buffer);
900 }
901
902 #endif /* WIN32 */
903
904 /*! @} */
905