Apache HTTPD
service.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/* This module ALONE requires the window message API from user.h
18 * and the default APR include of windows.h will omit it, so
19 * preload the API symbols now...
20 */
21
22#define _WINUSER_
23
24#include "apr.h"
25#include "apr_strings.h"
26#include "apr_lib.h"
27#if APR_HAS_UNICODE_FS
30#include <wchar.h>
31#endif
32
33#include "httpd.h"
34#include "http_log.h"
35#include "mpm_winnt.h"
36#include "ap_regkey.h"
37
38#ifdef NOUSER
39#undef NOUSER
40#endif
41#undef _WINUSER_
42#include <winuser.h>
43#include <time.h>
44
46
47/* Todo; clear up statics */
48static char *mpm_service_name = NULL;
49static char *mpm_display_name = NULL;
50
51#if APR_HAS_UNICODE_FS
53#endif
54
55typedef struct nt_service_ctx_t
56{
57 HANDLE mpm_thread; /* primary thread handle of the apache server */
58 HANDLE service_thread; /* thread service/monitor handle */
59 DWORD service_thread_id;/* thread service/monitor ID */
60 HANDLE service_init; /* controller thread init mutex */
61 HANDLE service_term; /* NT service thread kill signal */
65
67
68static int ReportStatusToSCMgr(int currentState, int waitHint,
70
71/* Rather than repeat this logic throughout, create an either-or wide or narrow
72 * implementation because we don't actually pass strings to OpenSCManager.
73 * This election is based on build time defines and runtime os version test.
74 */
75#undef OpenSCManager
77 const void *lpDatabase,
81 const void *lpDatabase,
83{
84 if (!pfn_OpenSCManager) {
85#if APR_HAS_UNICODE_FS
88#endif
89#if APR_HAS_ANSI_FS
92#endif
93 }
95}
96
97/* exit() for Win32 is macro mapped (horrible, we agree) that allows us
98 * to catch the non-zero conditions and inform the console process that
99 * the application died, and hang on to the console a bit longer.
100 *
101 * The macro only maps for http_main.c and other sources that include
102 * the service.h header, so we best assume it's an error to exit from
103 * _any_ other module.
104 *
105 * If ap_real_exit_code is reset to 0, it will not be set or trigger this
106 * behavior on exit. All service and child processes are expected to
107 * reset this flag to zero to avoid undesirable side effects.
108 */
110
112{
118 char *msg = "Note the errors or messages above, "
119 "and press the <ESC> key to exit. ";
122 char count[16];
123
125 return;
129 return;
130 if (!WriteConsole(hConErr, msg, (DWORD)strlen(msg), &result, NULL)
131 || !result)
132 return;
134 return;
136 return;
137
138 start = time(NULL);
139 do
140 {
141 while (PeekConsoleInput(hConIn, &in, 1, &result) && result)
142 {
143 if (!ReadConsoleInput(hConIn, &in, 1, &result) || !result)
144 return;
145 if ((in.EventType == KEY_EVENT) && in.Event.KeyEvent.bKeyDown
146 && (in.Event.KeyEvent.uChar.AsciiChar == 27))
147 return;
148 if (in.EventType == MOUSE_EVENT
149 && (in.Event.MouseEvent.dwEventFlags == DOUBLE_CLICK))
150 return;
151 }
152 remains = ((start + 30) - time(NULL));
153 sprintf(count, "%d...",
154 (int)remains); /* 30 or less, so can't overflow int */
155 if (!SetConsoleCursorPosition(hConErr, coninfo.dwCursorPosition))
156 return;
157 if (!WriteConsole(hConErr, count, (DWORD)strlen(count), &result, NULL)
158 || !result)
159 return;
160 }
161 while ((remains > 0) && WaitForSingleObject(hConIn, 1000) != WAIT_FAILED);
162}
163
165{
166 switch (ctrl_type)
167 {
168 case CTRL_BREAK_EVENT:
169 fprintf(stderr, "Apache server restarting...\n");
171 return TRUE;
172 case CTRL_C_EVENT:
173 fprintf(stderr, "Apache server interrupted...\n");
174 /* for Interrupt signals, shut down the server.
175 * Tell the system we have dealt with the signal
176 * without waiting for Apache to terminate.
177 */
179 return TRUE;
180
181 case CTRL_CLOSE_EVENT:
184 /* for Terminate signals, shut down the server.
185 * Wait for Apache to terminate, but respond
186 * after a reasonable time to tell the system
187 * that we did attempt to shut ourself down.
188 */
189 fprintf(stderr, "Apache server shutdown initiated...\n");
191 Sleep(30000);
192 return TRUE;
193 }
194
195 /* We should never get here, but this is (mostly) harmless */
196 return FALSE;
197}
198
199
204
205
211
212
217
218
219/**********************************
220 WinNT service control management
221 **********************************/
222
225{
226 int rv = APR_SUCCESS;
227
228 if (ctx->hServiceStatus)
229 {
231 ctx->ssStatus.dwWaitHint = 0;
232 ctx->ssStatus.dwCheckPoint = 0;
233 ctx->ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
235 }
236 else if (currentState == SERVICE_STOPPED) {
237 ctx->ssStatus.dwWaitHint = 0;
238 ctx->ssStatus.dwCheckPoint = 0;
239 /* An unexpected exit? Better to error! */
240 if (ctx->ssStatus.dwCurrentState != SERVICE_STOP_PENDING
241 && !ctx->ssStatus.dwServiceSpecificExitCode)
242 ctx->ssStatus.dwServiceSpecificExitCode = 1;
243 if (ctx->ssStatus.dwServiceSpecificExitCode)
244 ctx->ssStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
245 }
246 else {
247 ++ctx->ssStatus.dwCheckPoint;
248 ctx->ssStatus.dwControlsAccepted = 0;
249 if(waitHint)
250 ctx->ssStatus.dwWaitHint = waitHint;
251 }
252
253 ctx->ssStatus.dwCurrentState = currentState;
254
255 rv = SetServiceStatus(ctx->hServiceStatus, &ctx->ssStatus);
256 }
257 return(rv);
258}
259
260/* Note this works on Win2000 and later due to ChangeServiceConfig2
261 * Continue to test its existence, but at least drop the feature
262 * of revising service description tags prior to Win2000.
263 */
264
265/* borrowed from mpm_winnt.c */
266extern apr_pool_t *pconf;
267
268static void set_service_description(void)
269{
270 const char *full_description;
272
273 /* Nothing to do if we are a console
274 */
275 if (!mpm_service_name)
276 return;
277
278 /* Time to fix up the description, upon each successful restart
279 */
281
282 if ((ChangeServiceConfig2) &&
284 {
286
287#if APR_HAS_UNICODE_FS
289 {
293 }
294#endif /* APR_HAS_UNICODE_FS */
295#if APR_HAS_ANSI_FS
297 {
300 }
301#endif
302 if (schService) {
303 /* Cast is necessary, ChangeServiceConfig2 handles multiple
304 * object types, some volatile, some not.
305 */
306#if APR_HAS_UNICODE_FS
308 {
309 apr_size_t slen = strlen(full_description) + 1;
313 wslen * sizeof(apr_wchar_t));
316 &wslen);
317 if ((rv != APR_SUCCESS) || slen
319 /*SERVICE_CONFIG_DESCRIPTION*/,
322 }
323#endif /* APR_HAS_UNICODE_FS */
324#if APR_HAS_ANSI_FS
326 {
328 1 /* SERVICE_CONFIG_DESCRIPTION */,
331 }
332#endif
334 }
336 }
337}
338
339/* handle the SCM's ControlService() callbacks to our service */
340
343{
345
346 /* SHUTDOWN is offered before STOP, accept the first opportunity */
349 {
352 return (NO_ERROR);
353 }
355 {
358 return (NO_ERROR);
359 }
361 ReportStatusToSCMgr(globdat.ssStatus.dwCurrentState, 0, ctx);
362 return (NO_ERROR);
363 }
364
366}
367
368
369/* service_nt_main_fn is outside of the call stack and outside of the
370 * primary server thread... so now we _really_ need a placeholder!
371 * The winnt_rewrite_args has created and shared mpm_new_argv with us.
372 */
374
375#if APR_HAS_UNICODE_FS
377{
378 const char *ignored;
380 char *service_name;
381 apr_size_t wslen = wcslen(argv[0]) + 1;
382 apr_size_t slen = wslen * 3 - 2;
383
386
387 /* args and service names live in the same pool */
389
390 memset(&ctx->ssStatus, 0, sizeof(ctx->ssStatus));
391 ctx->ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
392 ctx->ssStatus.dwCurrentState = SERVICE_START_PENDING;
393 ctx->ssStatus.dwCheckPoint = 1;
394 if (!(ctx->hServiceStatus =
396 {
399 APLOGNO(00365) "Failure registering service handler");
400 return;
401 }
402
403 /* Report status, no errors, and buy 3 more seconds */
405
406 /* We need to append all the command arguments passed via StartService()
407 * to our running service... which just got here via the SCM...
408 * but we have no interest in argv[0] for the mpm_new_argv list.
409 */
410 if (argc > 1)
411 {
412 char **cmb_data, **cmb;
413 DWORD i;
414
416 cmb_data = malloc(mpm_new_argv->nalloc * sizeof(const char *));
417
418 /* mpm_new_argv remains first (of lower significance) */
421
422 /* Service args follow from StartService() invocation */
424 mpm_new_argv->elt_size * (argc - 1));
425
427
428 for (i = 1; i < argc; ++i)
429 {
430 wslen = wcslen(argv[i]) + 1;
431 slen = wslen * 3 - 2;
433 (void)apr_conv_ucs2_to_utf8(argv[i], &wslen, *(cmb++), &slen);
434 }
435
436 /* The replacement arg list is complete */
437 mpm_new_argv->elts = (char *)cmb_data;
439 }
440
441 /* Let the main thread continue now... but hang on to the
442 * signal_monitor event so we can take further action
443 */
444 SetEvent(ctx->service_init);
445
446 WaitForSingleObject(ctx->service_term, INFINITE);
447}
448#endif /* APR_HAS_UNICODE_FS */
449
450
451#if APR_HAS_ANSI_FS
453{
454 const char *ignored;
456
457 /* args and service names live in the same pool */
459
460 memset(&ctx->ssStatus, 0, sizeof(ctx->ssStatus));
461 ctx->ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
462 ctx->ssStatus.dwCurrentState = SERVICE_START_PENDING;
463 ctx->ssStatus.dwCheckPoint = 1;
464
465 if (!(ctx->hServiceStatus =
467 {
470 APLOGNO(10008) "Failure registering service handler");
471 return;
472 }
473
474 /* Report status, no errors, and buy 3 more seconds */
476
477 /* We need to append all the command arguments passed via StartService()
478 * to our running service... which just got here via the SCM...
479 * but we have no interest in argv[0] for the mpm_new_argv list.
480 */
481 if (argc > 1)
482 {
483 char **cmb_data;
484
486 cmb_data = malloc(mpm_new_argv->nalloc * sizeof(const char *));
487
488 /* mpm_new_argv remains first (of lower significance) */
491
492 /* Service args follow from StartService() invocation */
494 mpm_new_argv->elt_size * (argc - 1));
495
496 /* The replacement arg list is complete */
497 mpm_new_argv->elts = (char *)cmb_data;
499 }
500
501 /* Let the main thread continue now... but hang on to the
502 * signal_monitor event so we can take further action
503 */
504 SetEvent(ctx->service_init);
505
506 WaitForSingleObject(ctx->service_term, INFINITE);
507}
508#endif
509
510
512 {
513#if APR_HAS_UNICODE_FS
515 {
516 { L"", service_nt_main_fn_w },
517 { NULL, NULL }
518 };
519#endif /* APR_HAS_UNICODE_FS */
520#if APR_HAS_ANSI_FS
522 {
523 { "", service_nt_main_fn },
524 { NULL, NULL }
525 };
526#endif
527 apr_status_t rv;
528
529#if APR_HAS_UNICODE_FS
532#endif
533#if APR_HAS_ANSI_FS
536#endif
537 if (rv) {
538 rv = APR_SUCCESS;
539 }
540 else {
541 /* This is a genuine failure of the SCM. */
542 rv = apr_get_os_error();
544 APLOGNO(00366) "Error starting Windows service control "
545 "dispatcher");
546 }
547 return (rv);
548}
549
550
551/* The service configuration's is stored under the following trees:
552 *
553 * HKLM\System\CurrentControlSet\Services\[service name]
554 *
555 * \DisplayName
556 * \ImagePath
557 * \Parameters\ConfigArgs
558 */
559
560
562 const char *set_name)
563{
564 char key_name[MAX_PATH];
566 apr_status_t rv;
567
568 /* ### Needs improvement, on Win2K the user can _easily_
569 * change the display name to a string that doesn't reflect
570 * the internal service name + whitespace!
571 */
572 mpm_service_name = apr_palloc(p, strlen(set_name) + 1);
574#if APR_HAS_UNICODE_FS
576 {
577 apr_size_t slen = strlen(mpm_service_name) + 1;
582 if (rv != APR_SUCCESS)
583 return rv;
584 else if (slen)
585 return APR_ENAMETOOLONG;
586 }
587#endif /* APR_HAS_UNICODE_FS */
588
591 APR_READ, pconf);
592 if (rv == APR_SUCCESS) {
593 rv = ap_regkey_value_get(&mpm_display_name, key, "DisplayName", pconf);
595 }
596 if (rv != APR_SUCCESS) {
597 /* Take the given literal name if there is no service entry */
599 }
601
602 return rv;
603}
604
605
608 int fixed_args)
609{
611 char conf_key[MAX_PATH];
612 char **cmb_data;
613 apr_status_t rv;
615
618 if (rv == APR_SUCCESS) {
619 rv = ap_regkey_value_array_get(&svc_args, key, "ConfigArgs", p);
621 }
622 if (rv != APR_SUCCESS) {
623 if (rv == ERROR_FILE_NOT_FOUND) {
625 "No ConfigArgs registered for the '%s' service, "
626 "perhaps this service is not installed?",
628 return APR_SUCCESS;
629 }
630 else
631 return (rv);
632 }
633
634 if (!svc_args || svc_args->nelts == 0) {
635 return (APR_SUCCESS);
636 }
637
638 /* Now we have the mpm_service_name arg, and the mpm_runservice_nt()
639 * call appended the arguments passed by StartService(), so it's
640 * time to _prepend_ the default arguments for the server from
641 * the service's default arguments (all others override them)...
642 */
643 args->nalloc = args->nelts + svc_args->nelts;
644 cmb_data = malloc(args->nalloc * sizeof(const char *));
645
646 /* First three args (argv[0], -f, path) remain first */
647 memcpy(cmb_data, args->elts, args->elt_size * fixed_args);
648
649 /* Service args follow from service registry array */
651 svc_args->elt_size * svc_args->nelts);
652
653 /* Remaining new args follow */
655 (const char **)args->elts + fixed_args,
656 args->elt_size * (args->nelts - fixed_args));
657
658 args->elts = (char *)cmb_data;
659 args->nelts = args->nalloc;
660
661 return APR_SUCCESS;
662}
663
664
665static void service_stopped(void)
666{
667 /* Still have a thread & window to clean up, so signal now */
669 {
670 /* Stop logging to the event log */
672
673 /* Cause the service_nt_main_fn to complete */
675
677
680 }
681}
682
683
685{
688 HANDLE waitfor[2];
689
690 /* Prevent holding open the (hidden) console */
692
693 /* GetCurrentThread returns a psuedo-handle, we need
694 * a real handle for another thread to wait upon.
695 */
698 return APR_ENOTHREAD;
699 }
700
704 return APR_EGENERAL;
705 }
706
711
712 if (!globdat.service_thread) {
713 return APR_ENOTHREAD;
714 }
715
718
719 /* Wait for controlling thread init or termination */
721 return APR_ENOTHREAD;
722 }
723
726 return APR_SUCCESS;
727}
728
729
736
737
742
743
745 const char * const * argv, int reconfig)
746{
747 char key_name[MAX_PATH];
748 char *launch_cmd;
750 apr_status_t rv;
753 DWORD rc;
754#if APR_HAS_UNICODE_FS
757#endif
758
759 fprintf(stderr, reconfig ? "Reconfiguring the '%s' service\n"
760 : "Installing the '%s' service\n",
762
763#if APR_HAS_UNICODE_FS
765 {
766 apr_size_t slen = strlen(mpm_display_name) + 1;
768 display_name_w = apr_palloc(ptemp, wslen * sizeof(apr_wchar_t));
771 if (rv != APR_SUCCESS)
772 return rv;
773 else if (slen)
774 return APR_ENAMETOOLONG;
775
776 launch_cmd_w = apr_palloc(ptemp, (MAX_PATH + 17) * sizeof(apr_wchar_t));
777 launch_cmd_w[0] = L'"';
779 wcscpy(launch_cmd_w + rc + 1, L"\" -k runservice");
780 }
781#endif /* APR_HAS_UNICODE_FS */
782#if APR_HAS_ANSI_FS
784 {
785 launch_cmd = apr_palloc(ptemp, MAX_PATH + 17);
786 launch_cmd[0] = '"';
788 strcpy(launch_cmd + rc + 1, "\" -k runservice");
789 }
790#endif
791 if (rc == 0) {
792 rv = apr_get_os_error();
794 APLOGNO(00368) "GetModuleFileName failed");
795 return rv;
796 }
797
798 schSCManager = OpenSCManager(NULL, NULL, /* local, default database */
800 if (!schSCManager) {
801 rv = apr_get_os_error();
803 APLOGNO(00369) "Failed to open the Windows service "
804 "manager, perhaps you forgot to log in as Administrator?");
805 return (rv);
806 }
807
808 if (reconfig) {
809#if APR_HAS_UNICODE_FS
811 {
814 }
815#endif /* APR_HAS_UNICODE_FS */
816#if APR_HAS_ANSI_FS
818 {
821 }
822#endif
823 if (!schService) {
824 rv = apr_get_os_error();
827 APLOGNO(00373) "Failed to open the '%s' service",
829 return (rv);
830 }
831
832#if APR_HAS_UNICODE_FS
834 {
840 L"Tcpip\0Afd\0", NULL, NULL,
842 }
843#endif /* APR_HAS_UNICODE_FS */
844#if APR_HAS_ANSI_FS
846 {
852 "Tcpip\0Afd\0", NULL, NULL,
854 }
855#endif
856 if (!rc) {
859 APLOGNO(02652) "ChangeServiceConfig failed");
860
861 /* !schService aborts configuration below */
864 }
865 }
866 else {
867 /* RPCSS is the Remote Procedure Call (RPC) Locator required
868 * for DCOM communication pipes. I am far from convinced we
869 * should add this to the default service dependencies, but
870 * be warned that future apache modules or ISAPI dll's may
871 * depend on it.
872 */
873#if APR_HAS_UNICODE_FS
875 {
876 schService = CreateServiceW(schSCManager, // SCManager database
877 mpm_service_name_w, // name of service
878 display_name_w, // name to display
879 SERVICE_ALL_ACCESS, // access required
880 SERVICE_WIN32_OWN_PROCESS, // service type
881 SERVICE_AUTO_START, // start type
882 SERVICE_ERROR_NORMAL, // error control type
883 launch_cmd_w, // service's binary
884 NULL, // no load svc group
885 NULL, // no tag identifier
886 L"Tcpip\0Afd\0", // dependencies
887 NULL, // use SYSTEM account
888 NULL); // no password
889 }
890#endif /* APR_HAS_UNICODE_FS */
891#if APR_HAS_ANSI_FS
893 {
894 schService = CreateService(schSCManager, // SCManager database
895 mpm_service_name, // name of service
896 mpm_display_name, // name to display
897 SERVICE_ALL_ACCESS, // access required
898 SERVICE_WIN32_OWN_PROCESS, // service type
899 SERVICE_AUTO_START, // start type
900 SERVICE_ERROR_NORMAL, // error control type
901 launch_cmd, // service's binary
902 NULL, // no load svc group
903 NULL, // no tag identifier
904 "Tcpip\0Afd\0", // dependencies
905 NULL, // use SYSTEM account
906 NULL); // no password
907 }
908#endif
909 if (!schService)
910 {
911 rv = apr_get_os_error();
913 APLOGNO(00370) "Failed to create the '%s' service",
916 return (rv);
917 }
918 }
919
922
924
925 /* Store the service ConfigArgs in the registry...
926 */
930 if (rv == APR_SUCCESS) {
931 rv = ap_regkey_value_array_set(key, "ConfigArgs", argc, argv, pconf);
933 }
934 if (rv != APR_SUCCESS) {
936 APLOGNO(00371) "Failed to store ConfigArgs for the "
937 "'%s' service in the registry.", mpm_display_name);
938 return (rv);
939 }
940 fprintf(stderr, "The '%s' service is successfully installed.\n",
942 return APR_SUCCESS;
943}
944
945
947{
948 apr_status_t rv;
951
952 fprintf(stderr, "Removing the '%s' service\n", mpm_display_name);
953
954 schSCManager = OpenSCManager(NULL, NULL, /* local, default database */
956 if (!schSCManager) {
957 rv = apr_get_os_error();
959 APLOGNO(10009) "Failed to open the Windows service "
960 "manager, perhaps you forgot to log in as Administrator?");
961 return (rv);
962 }
963
964#if APR_HAS_UNICODE_FS
966 {
968 }
969#endif /* APR_HAS_UNICODE_FS */
970#if APR_HAS_ANSI_FS
972 {
974 }
975#endif
976 if (!schService) {
977 rv = apr_get_os_error();
979 APLOGNO(10010) "Failed to open the '%s' service",
981 return (rv);
982 }
983
984 /* assure the service is stopped before continuing
985 *
986 * This may be out of order... we might not be able to be
987 * granted all access if the service is running anyway.
988 *
989 * And do we want to make it *this easy* for them
990 * to uninstall their service unintentionally?
991 */
992 /* ap_stop_service(schService);
993 */
994
995 if (DeleteService(schService) == 0) {
996 rv = apr_get_os_error();
998 APLOGNO(00374) "Failed to delete the '%s' service",
1000 return (rv);
1001 }
1002
1005
1006 fprintf(stderr, "The '%s' service has been removed successfully.\n",
1008 return APR_SUCCESS;
1009}
1010
1011
1012/* signal_service_transition is a simple thunk to signal the service
1013 * and monitor its successful transition. If the signal passed is 0,
1014 * then the caller is assumed to already have performed some service
1015 * operation to be monitored (such as StartService), and no actual
1016 * ControlService signal is sent.
1017 */
1018
1020 DWORD pending, DWORD complete)
1021{
1023 return FALSE;
1024
1025 do {
1026 Sleep(1000);
1028 return FALSE;
1029 } while (globdat.ssStatus.dwCurrentState == pending);
1030
1031 return (globdat.ssStatus.dwCurrentState == complete);
1032}
1033
1034
1036 const char * const * argv)
1037{
1038 apr_status_t rv;
1041
1042 fprintf(stderr, "Starting the '%s' service\n", mpm_display_name);
1043
1044 schSCManager = OpenSCManager(NULL, NULL, /* local, default database */
1046 if (!schSCManager) {
1047 rv = apr_get_os_error();
1049 APLOGNO(10011) "Failed to open the Windows service "
1050 "manager, perhaps you forgot to log in as Administrator?");
1051 return (rv);
1052 }
1053
1054#if APR_HAS_UNICODE_FS
1056 {
1059 }
1060#endif /* APR_HAS_UNICODE_FS */
1061#if APR_HAS_ANSI_FS
1063 {
1066 }
1067#endif
1068 if (!schService) {
1069 rv = apr_get_os_error();
1071 APLOGNO(10012) "Failed to open the '%s' service",
1074 return (rv);
1075 }
1076
1078 && (globdat.ssStatus.dwCurrentState == SERVICE_RUNNING)) {
1080 APLOGNO(00377) "The '%s' service is already started!",
1084 return 0;
1085 }
1086
1087 rv = APR_EINIT;
1088#if APR_HAS_UNICODE_FS
1090 {
1091 LPWSTR *start_argv_w = malloc((argc + 1) * sizeof(LPCWSTR));
1092 int i;
1093
1094 for (i = 0; i < argc; ++i)
1095 {
1096 apr_size_t slen = strlen(argv[i]) + 1;
1098 start_argv_w[i] = malloc(wslen * sizeof(WCHAR));
1100 if (rv != APR_SUCCESS)
1101 return rv;
1102 else if (slen)
1103 return APR_ENAMETOOLONG;
1104 }
1106
1108 && signal_service_transition(schService, 0, /* test only */
1111 rv = APR_SUCCESS;
1112 }
1113#endif /* APR_HAS_UNICODE_FS */
1114#if APR_HAS_ANSI_FS
1116 {
1117 char **start_argv = malloc((argc + 1) * sizeof(const char *));
1118 memcpy(start_argv, argv, argc * sizeof(const char *));
1119 start_argv[argc] = NULL;
1120
1122 && signal_service_transition(schService, 0, /* test only */
1125 rv = APR_SUCCESS;
1126 }
1127#endif
1128 if (rv != APR_SUCCESS)
1129 rv = apr_get_os_error();
1130
1133
1134 if (rv == APR_SUCCESS)
1135 fprintf(stderr, "The '%s' service is running.\n", mpm_display_name);
1136 else
1138 "Failed to start the '%s' service",
1140
1141 return rv;
1142}
1143
1144
1145/* signal is zero to stop, non-zero for restart */
1146
1148{
1149 int success = FALSE;
1152
1153 schSCManager = OpenSCManager(NULL, NULL, /* default machine & database */
1155
1156 if (!schSCManager) {
1159 APLOGNO(10013) "Failed to open the Windows service "
1160 "manager, perhaps you forgot to log in as Administrator?");
1161 return;
1162 }
1163
1164#if APR_HAS_UNICODE_FS
1166 {
1171 }
1172#endif /* APR_HAS_UNICODE_FS */
1173#if APR_HAS_ANSI_FS
1175 {
1180 }
1181#endif
1182 if (schService == NULL) {
1183 /* Could not open the service */
1186 APLOGNO(10014) "Failed to open the '%s' service",
1189 return;
1190 }
1191
1195 APLOGNO(00381) "Query of the '%s' service failed",
1199 return;
1200 }
1201
1202 if (!signal && (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED)) {
1203 fprintf(stderr, "The '%s' service is not started.\n", mpm_display_name);
1206 return;
1207 }
1208
1209 fprintf(stderr, signal ? "The '%s' service is restarting.\n"
1210 : "The '%s' service is stopping.\n",
1212
1213 if (!signal)
1218 else if (globdat.ssStatus.dwCurrentState == SERVICE_STOPPED) {
1219 mpm_service_start(ptemp, 0, NULL);
1222 return;
1223 }
1224 else
1229
1232
1233 if (success)
1234 fprintf(stderr, signal ? "The '%s' service has restarted.\n"
1235 : "The '%s' service has stopped.\n",
1237 else
1238 fprintf(stderr, signal ? "Failed to restart the '%s' service.\n"
1239 : "Failed to stop the '%s' service.\n",
1241}
#define AP_DECLARE_DATA
Definition ap_config.h:89
APR-style Win32 Registry Manipulation.
#define TRUE
Definition abts.h:38
#define FALSE
Definition abts.h:35
apr_uint16_t apr_wchar_t
#define WaitForMultipleObjects(d1, ah, b, d2)
#define SetEvent(h)
#define GetStdHandle(d)
#define CreateThread(sd, d1, fn, pv, d2, pd3)
#define GetCurrentProcess()
#define GetCurrentThread()
#define DuplicateHandle(h1, h2, h3, ph4, d1, b, d2)
#define CloseHandle(h)
#define WaitForSingleObject(h, d)
APR general purpose library routines.
APR Strings library.
#define APLOG_USE_MODULE(foo)
const char * ap_get_server_description(void)
Definition core.c:3587
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_STARTUP
Definition http_log.h:105
#define APLOG_INFO
Definition http_log.h:70
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_CRIT
Definition http_log.h:66
DWORD stack_res_flag
void mpm_start_child_console_handler(void)
Definition service.c:213
apr_status_t mpm_service_start(apr_pool_t *ptemp, int argc, const char *const *argv)
Definition service.c:1035
apr_status_t mpm_service_to_start(const char **display_name, apr_pool_t *p)
Definition service.c:684
apr_status_t mpm_service_set_name(apr_pool_t *p, const char **display_name, const char *set_name)
Definition service.c:561
void mpm_signal_service(apr_pool_t *ptemp, int signal)
Definition service.c:1147
#define SERVICECONFIG
Definition mpm_winnt.h:39
void hold_console_open_on_error(void)
Definition service.c:111
void mpm_start_console_handler(void)
Definition service.c:206
#define SERVICE_APACHE_RESTART
Definition mpm_winnt.h:33
void ap_signal_parent(ap_signal_parent_e type)
#define SERVICEPARAMS
Definition mpm_winnt.h:40
void mpm_service_stopping(void)
Definition service.c:738
apr_status_t mpm_service_uninstall(void)
Definition service.c:946
apr_status_t mpm_service_started(void)
Definition service.c:730
apr_status_t mpm_service_install(apr_pool_t *ptemp, int argc, const char *const *argv, int reconfig)
Definition service.c:744
void mpm_nt_eventlog_stderr_flush(void)
apr_status_t mpm_merge_service_args(apr_pool_t *p, apr_array_header_t *args, int fixed_args)
Definition service.c:606
@ SIGNAL_PARENT_SHUTDOWN
Definition mpm_winnt.h:84
@ SIGNAL_PARENT_RESTART
Definition mpm_winnt.h:85
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENAMETOOLONG
Definition apr_errno.h:655
#define APR_ENOTHREAD
Definition apr_errno.h:309
#define APR_EINIT
Definition apr_errno.h:474
unsigned int count
Definition apr_md5.h:152
apr_file_t apr_off_t start
apr_brigade_flush void * ctx
const char apr_ssize_t slen
Definition apr_encode.h:168
apr_redis_t * rc
Definition apr_redis.h:173
#define BOOL
Definition ssl_private.h:81
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
#define apr_get_os_error()
Definition apr_errno.h:1217
int apr_status_t
Definition apr_errno.h:44
const char * key
#define APR_READ
Definition apr_file_io.h:93
#define APR_WRITE
Definition apr_file_io.h:94
#define APR_CREATE
Definition apr_file_io.h:95
apr_array_header_t ** result
apr_pool_t int argc
Definition apr_getopt.h:104
apr_int32_t in
const char const char *const * args
Apache Logging library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
const char * argv[3]
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
WinNT MPM specific.
static const char * display_name
Definition nt_eventlog.c:25
apr_array_header_t * mpm_new_argv
static nt_service_ctx_t globdat
Definition service.c:66
static DWORD WINAPI service_nt_dispatch_thread(LPVOID nada)
Definition service.c:511
static int signal_service_transition(SC_HANDLE schService, DWORD signal, DWORD pending, DWORD complete)
Definition service.c:1019
apr_pool_t * pconf
static DWORD WINAPI service_nt_ctrl(DWORD dwCtrlCode, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
Definition service.c:341
static BOOL CALLBACK console_control_handler(DWORD ctrl_type)
Definition service.c:164
static fpt_OpenSCManager pfn_OpenSCManager
Definition service.c:79
static char * mpm_display_name
Definition service.c:49
static int ReportStatusToSCMgr(int currentState, int waitHint, nt_service_ctx_t *ctx)
Definition service.c:223
static char * mpm_service_name
Definition service.c:48
static void service_stopped(void)
Definition service.c:665
static APR_INLINE SC_HANDLE OpenSCManager(const void *lpMachine, const void *lpDatabase, DWORD dwAccess)
Definition service.c:80
static void stop_console_handler(void)
Definition service.c:200
int ap_real_exit_code
Definition service.c:109
static void set_service_description(void)
Definition service.c:268
SC_HANDLE(WINAPI * fpt_OpenSCManager)(const void *lpMachine, const void *lpDatabase, DWORD dwAccess)
Definition service.c:76
apr_pool_t * pool
Definition apr_tables.h:64
SERVICE_STATUS ssStatus
Definition service.c:62
SERVICE_STATUS_HANDLE hServiceStatus
Definition service.c:63
HANDLE service_init
Definition service.c:60
HANDLE mpm_thread
Definition service.c:57
HANDLE service_thread
Definition service.c:58
HANDLE service_term
Definition service.c:61
DWORD service_thread_id
Definition service.c:59
#define ELSE_WIN_OS_IS_ANSI
typedef HANDLE(WINAPI *apr_winapi_fpt_CreateToolhelp32Snapshot)(DWORD dwFlags
#define IF_WIN_OS_IS_UNICODE
typedef DWORD(WINAPI *apr_winapi_fpt_GetCompressedFileSizeA)(IN LPCSTR lpFileName