]> git.ipfire.org Git - thirdparty/squid.git/blob - src/win32.cc
Fix Stack which was broken in HEAD. Also update bootstrap.sh for newer automake and...
[thirdparty/squid.git] / src / win32.cc
1
2 /*
3 * $Id: win32.cc,v 1.12 2004/12/20 14:52:28 robertc Exp $
4 *
5 * * * * * * * * Legal stuff * * * * * * *
6 *
7 * (C) 2001 Guido Serassio <serassio@libero.it>,
8 * inspired by previous work by Romeo Anghelache & Eric Stern.
9 *
10 * SQUID Web Proxy Cache http://www.squid-cache.org/
11 * ----------------------------------------------------------
12 *
13 * Squid is the result of efforts by numerous individuals from
14 * the Internet community; see the CONTRIBUTORS file for full
15 * details. Many organizations have provided support for Squid's
16 * development; see the SPONSORS file for full details. Squid is
17 * Copyrighted (C) 2001 by the Regents of the University of
18 * California; see the COPYRIGHT file for full details. Squid
19 * incorporates software developed and/or copyrighted by other
20 * sources; see the CREDITS file for full details.
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
35 *
36 */
37
38 #ifndef WIN32_C
39 #define WIN32_C
40
41 #include "squid.h"
42
43 #include "squid_windows.h"
44
45 static unsigned int GetOSVersion();
46 void WIN32_svcstatusupdate(DWORD, DWORD);
47 void WINAPI WIN32_svcHandler(DWORD);
48 #if USE_WIN32_SERVICE
49 static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int);
50 static int WIN32_create_key(void);
51 static void WIN32_build_argv (char *);
52 #endif
53 extern "C" void WINAPI SquidMain(DWORD, char **);
54
55 static int Squid_Aborting = 0;
56 #if USE_WIN32_SERVICE
57 static SERVICE_STATUS svcStatus;
58 static SERVICE_STATUS_HANDLE svcHandle;
59 static int WIN32_argc;
60 static char ** WIN32_argv;
61 static char * WIN32_module_name;
62
63 #define VENDOR "GNU"
64 static char VENDORString[] = VENDOR;
65 #define SOFTWARENAME "Squid"
66 static char SOFTWARENAMEString[] = SOFTWARENAME;
67 #define WIN32_VERSION "3.0"
68 static char WIN32_VERSIONString[] = WIN32_VERSION;
69 #define SOFTWARE "SOFTWARE"
70 static char SOFTWAREString[] = SOFTWARE;
71 #define COMMANDLINE "CommandLine"
72 #define CONFIGFILE "ConfigFile"
73 #undef ChangeServiceConfig2
74 typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID);
75 #ifdef UNICODE
76 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
77 #else
78 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
79 #endif
80 static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } };
81 static char Squid_ServiceDescriptionString[] = SOFTWARENAME " " VERSION " WWW Proxy Server";
82 static SERVICE_DESCRIPTION Squid_ServiceDescription = { Squid_ServiceDescriptionString };
83 static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { INFINITE, NULL, NULL, 1, Squid_SCAction };
84 static char REGKEY[256]=SOFTWARE"\\"VENDOR"\\"SOFTWARENAME"\\"WIN32_VERSION"\\";
85 static char *keys[] = {
86 SOFTWAREString, /* key[0] */
87 VENDORString, /* key[1] */
88 SOFTWARENAMEString, /* key[2] */
89 WIN32_VERSIONString, /* key[3] */
90 NULL, /* key[4] */
91 NULL /* key[5] */
92 };
93 #endif
94
95 /* ====================================================================== */
96 /* LOCAL FUNCTIONS */
97 /* ====================================================================== */
98
99 #if USE_WIN32_SERVICE
100 static int
101 WIN32_create_key(void)
102 {
103 int index;
104 HKEY hKey;
105 HKEY hKeyNext;
106 int retval;
107 LONG rv;
108
109 hKey = HKEY_LOCAL_MACHINE;
110 index = 0;
111 retval = 0;
112
113 /* Walk the tree, creating at each stage if necessary */
114
115 while (keys[index]) {
116 unsigned long result;
117 rv = RegCreateKeyEx(hKey, keys[index], /* subkey */
118 0, /* reserved */
119 NULL, /* class */
120 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyNext, &result);
121
122 if (rv != ERROR_SUCCESS) {
123 fprintf(stderr, "RegCreateKeyEx(%s),%d\n", keys[index], (int) rv);
124 retval = -4;
125 }
126
127 /* Close the old key */
128 rv = RegCloseKey(hKey);
129
130 if (rv != ERROR_SUCCESS) {
131 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
132
133 if (retval == 0) {
134 /* Keep error status from RegCreateKeyEx, if any */
135 retval = -4;
136 }
137 }
138
139 if (retval) {
140 break;
141 }
142
143 hKey = hKeyNext;
144 index++;
145 }
146
147 if (keys[index] == NULL) {
148 /* Close the final key we opened, if we walked the entire
149 * tree
150 */
151 rv = RegCloseKey(hKey);
152
153 if (rv != ERROR_SUCCESS) {
154 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
155
156 if (retval == 0) {
157 /* Keep error status from RegCreateKeyEx, if any */
158 retval = -4;
159 }
160 }
161 }
162
163 return retval;
164 }
165
166 static int
167 WIN32_StoreKey(const char *key, DWORD type, unsigned char *value,
168 int value_size)
169 {
170 LONG rv;
171 HKEY hKey;
172 int retval;
173
174 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
175
176 if (rv == ERROR_FILE_NOT_FOUND) {
177 /* Key could not be opened -- try to create it
178 */
179
180 if (WIN32_create_key() < 0) {
181 /* Creation failed (error already reported) */
182 return -4;
183 }
184
185 /* Now it has been created we should be able to open it
186 */
187 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
188
189 if (rv == ERROR_FILE_NOT_FOUND) {
190 fprintf(stderr, "Registry does not contain key %s after creation\n",
191 REGKEY);
192 return -1;
193 }
194 }
195
196 if (rv != ERROR_SUCCESS) {
197 fprintf(stderr, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv);
198 return -4;
199 }
200
201 /* Now set the value and data */
202 rv = RegSetValueEx(hKey, key, /* value key name */
203 0, /* reserved */
204 type, /* type */
205 value, /* value data */
206 (DWORD) value_size); /* for size of "value" */
207
208 retval = 0; /* Return value */
209
210 if (rv != ERROR_SUCCESS) {
211 fprintf(stderr, "RegQueryValueEx(key %s),%d\n", key, (int) rv);
212 retval = -4;
213 } else {
214 fprintf(stderr, "Registry stored HKLM\\%s\\%s value %s\n",
215 REGKEY,
216 key,
217 type == REG_SZ ? value : (unsigned char *) "(not displayable)");
218 }
219
220 /* Make sure we close the key even if there was an error storing
221 * the data
222 */
223 rv = RegCloseKey(hKey);
224
225 if (rv != ERROR_SUCCESS) {
226 fprintf(stderr, "RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv);
227
228 if (retval == 0) {
229 /* Keep error status from RegQueryValueEx, if any */
230 retval = -4;
231 }
232 }
233
234 return retval;
235 }
236
237 #endif
238
239 static unsigned int
240 GetOSVersion()
241 {
242 OSVERSIONINFO osvi;
243
244 safe_free(WIN32_OS_string);
245 memset(&osvi, '\0', sizeof(OSVERSIONINFO));
246 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
247 GetVersionEx((OSVERSIONINFO *) & osvi);
248
249 switch (osvi.dwPlatformId) {
250
251 case VER_PLATFORM_WIN32_NT:
252
253 if (osvi.dwMajorVersion <= 4) {
254 WIN32_OS_string = xstrdup("Windows NT");
255 return _WIN_OS_WINNT;
256 }
257
258 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) {
259 WIN32_OS_string = xstrdup("Windows 2000");
260 return _WIN_OS_WIN2K;
261 }
262
263 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) {
264 WIN32_OS_string = xstrdup("Windows XP");
265 return _WIN_OS_WINXP;
266 }
267
268 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2)) {
269 WIN32_OS_string = xstrdup("Windows Server 2003");
270 return _WIN_OS_WINNET;
271 }
272
273 break;
274
275 case VER_PLATFORM_WIN32_WINDOWS:
276
277 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)) {
278 WIN32_OS_string = xstrdup("Windows 95");
279 return _WIN_OS_WIN95;
280 }
281
282 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 10)) {
283 WIN32_OS_string = xstrdup("Windows 98");
284 return _WIN_OS_WIN98;
285 }
286
287 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 90)) {
288 WIN32_OS_string = xstrdup("Windows Me");
289 return _WIN_OS_WINME;
290 }
291
292 break;
293
294 case VER_PLATFORM_WIN32s:
295 WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S");
296 return _WIN_OS_WIN32S;
297 break;
298
299 default:
300 break;
301 }
302
303 WIN32_OS_string = xstrdup("Unknown Windows system");
304 return _WIN_OS_UNKNOWN;
305 }
306
307 #if USE_WIN32_SERVICE
308 /* Build argv, argc from string passed from Windows. */
309 static void WIN32_build_argv(char *cmd)
310 {
311 int argvlen = 0;
312 char *word;
313
314 WIN32_argc = 1;
315 WIN32_argv = (char **) xmalloc ((WIN32_argc+1) * sizeof (char *));
316 WIN32_argv[0]=xstrdup(WIN32_module_name);
317 /* Scan command line until there is nothing left. */
318
319 while (*cmd) {
320 /* Ignore spaces */
321
322 if (xisspace(*cmd)) {
323 cmd++;
324 continue;
325 }
326
327 /* Found the beginning of an argument. */
328 word = cmd;
329
330 while (*cmd) {
331 cmd++; /* Skip over this character */
332
333 if (xisspace(*cmd)) /* End of argument if space */
334 break;
335 }
336
337 if (*cmd)
338 *cmd++ = '\0'; /* Terminate `word' */
339
340 /* See if we need to allocate more space for argv */
341 if (WIN32_argc >= argvlen) {
342 argvlen = WIN32_argc + 1;
343 WIN32_argv = (char **) xrealloc (WIN32_argv, (1 + argvlen) * sizeof (char *));
344 }
345
346 /* Add word to argv file. */
347 WIN32_argv[WIN32_argc++] = word;
348 }
349
350 WIN32_argv[WIN32_argc] = NULL;
351 }
352
353 #endif
354
355 /* ====================================================================== */
356 /* PUBLIC FUNCTIONS */
357 /* ====================================================================== */
358
359 void
360 WIN32_Abort(int sig)
361 {
362 #if USE_WIN32_SERVICE
363 svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
364 svcStatus.dwServiceSpecificExitCode = 1;
365 #endif
366
367 Squid_Aborting = 1;
368 WIN32_Exit();
369 }
370
371 void
372 WIN32_Exit()
373 {
374 #if USE_WIN32_SERVICE
375
376 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
377 if (!Squid_Aborting) {
378 svcStatus.dwCurrentState = SERVICE_STOPPED;
379 SetServiceStatus(svcHandle, &svcStatus);
380 }
381 }
382
383 #endif
384
385 _exit(0);
386 }
387
388 #if USE_WIN32_SERVICE
389 int WIN32_Subsystem_Init(int * argc, char *** argv)
390 #else
391 int
392 WIN32_Subsystem_Init()
393 #endif
394 {
395 WIN32_OS_version = GetOSVersion();
396
397 if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S))
398 return 1;
399
400 if (atexit(WIN32_Exit) != 0)
401 return 1;
402
403 #if USE_WIN32_SERVICE
404
405 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE)
406 {
407 char path[512];
408 HKEY hndKey;
409
410 if (signal(SIGABRT, WIN32_Abort) == SIG_ERR)
411 return 1;
412
413 /* Register the service Handler function */
414 svcHandle =
415 RegisterServiceCtrlHandler(WIN32_Service_name,
416 WIN32_svcHandler);
417
418 if (svcHandle == 0)
419 return 1;
420
421 /* Set Process work dir to directory cointaining squid.exe */
422 GetModuleFileName(NULL, path, 512);
423
424 WIN32_module_name=xstrdup(path);
425
426 path[strlen(path) - 10] = '\0';
427
428 if (SetCurrentDirectory(path) == 0)
429 return 1;
430
431 safe_free(ConfigFile);
432
433 /* get config file from Windows Registry */
434 if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY, &hndKey) == ERROR_SUCCESS) {
435 DWORD Type = 0;
436 DWORD Size = 0;
437 LONG Result;
438 Result =
439 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
440
441 if (Result == ERROR_SUCCESS && Size) {
442 ConfigFile = static_cast<char *>(xmalloc(Size));
443 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile,
444 &Size);
445 } else
446 ConfigFile = xstrdup(DefaultConfigFile);
447
448 Size = 0;
449
450 Type = 0;
451
452 Result =
453 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
454
455 if (Result == ERROR_SUCCESS && Size) {
456 WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
457 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, (unsigned char *)WIN32_Service_Command_Line,
458 &Size);
459 } else
460 WIN32_Service_Command_Line = xstrdup("");
461
462 RegCloseKey(hndKey);
463 } else {
464 ConfigFile = xstrdup(DefaultConfigFile);
465 WIN32_Service_Command_Line = xstrdup("");
466 }
467
468 WIN32_build_argv(WIN32_Service_Command_Line);
469 *argc = WIN32_argc;
470 *argv = WIN32_argv;
471 /* Set Service Status to SERVICE_START_PENDING */
472 svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
473 svcStatus.dwCurrentState = SERVICE_START_PENDING;
474 svcStatus.dwControlsAccepted =
475 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
476 svcStatus.dwWin32ExitCode = 0;
477 svcStatus.dwServiceSpecificExitCode = 0;
478 svcStatus.dwCheckPoint = 0;
479 svcStatus.dwWaitHint = 10000;
480 SetServiceStatus(svcHandle, &svcStatus);
481
482 }
483
484 #endif
485
486 return 0;
487 }
488
489 #if USE_WIN32_SERVICE
490 void
491 WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
492 {
493 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
494 svcStatus.dwCheckPoint++;
495 svcStatus.dwWaitHint = WaitHint;
496 svcStatus.dwCurrentState = svcstate;
497 SetServiceStatus(svcHandle, &svcStatus);
498 }
499 }
500
501 VOID WINAPI
502 WIN32_svcHandler(DWORD Opcode)
503 {
504 DWORD status;
505
506 switch (Opcode) {
507
508 case _WIN_SQUID_SERVICE_CONTROL_STOP:
509
510 case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN:
511 /* Do whatever it takes to stop here. */
512 svcStatus.dwWin32ExitCode = 0;
513 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
514 svcStatus.dwCheckPoint = 0;
515 svcStatus.dwWaitHint = 10000;
516 shut_down(SIGTERM);
517
518 if (!SetServiceStatus(svcHandle, &svcStatus)) {
519 status = GetLastError();
520 debug(1, 1) ("SetServiceStatus error %ld\n", status);
521 }
522
523 debug(1, 1) ("Leaving Squid service\n");
524 return;
525
526 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE:
527 /* Fall through to send current status. */
528
529 if (!SetServiceStatus(svcHandle, &svcStatus)) {
530 status = GetLastError();
531 debug(1, 1) ("SetServiceStatus error %ld\n", status);
532 }
533
534 break;
535
536 case _WIN_SQUID_SERVICE_CONTROL_ROTATE:
537 rotate_logs(SIGUSR1);
538 break;
539
540 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE:
541 reconfigure(SIGHUP);
542 break;
543
544 case _WIN_SQUID_SERVICE_CONTROL_DEBUG:
545 sigusr2_handle(SIGUSR2);
546 break;
547
548 case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT:
549 /* Do whatever it takes to stop here. */
550 svcStatus.dwWin32ExitCode = 0;
551 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
552 svcStatus.dwCheckPoint = 0;
553 svcStatus.dwWaitHint = 10000;
554 shut_down(SIGINT);
555
556 if (!SetServiceStatus(svcHandle, &svcStatus)) {
557 status = GetLastError();
558 debug(1, 1) ("SetServiceStatus error %ld\n", status);
559 }
560
561 debug(1, 1) ("Leaving Squid service\n");
562 break;
563
564 default:
565 debug(1, 1) ("Unrecognized opcode %ld\n", Opcode);
566 }
567
568 return;
569 }
570
571 void
572 WIN32_RemoveService()
573 {
574 SC_HANDLE schService;
575 SC_HANDLE schSCManager;
576
577 if (!WIN32_Service_name)
578 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
579
580 strcat(REGKEY, WIN32_Service_name);
581
582 keys[4] = WIN32_Service_name;
583
584 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
585 NULL, /* database (NULL == default) */
586 SC_MANAGER_ALL_ACCESS /* access required */
587 );
588
589 if (!schSCManager)
590 fprintf(stderr, "OpenSCManager failed\n");
591 else {
592 schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS);
593
594 if (schService == NULL)
595 fprintf(stderr, "OpenService failed\n");
596
597 /* Could not open the service */
598 else {
599 /* try to stop the service */
600
601 if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
602 &svcStatus)) {
603 sleep(1);
604
605 while (QueryServiceStatus(schService, &svcStatus)) {
606 if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
607 sleep(1);
608 else
609 break;
610 }
611 }
612
613 /* now remove the service */
614 if (DeleteService(schService) == 0)
615 fprintf(stderr, "DeleteService failed.\n");
616 else
617 printf("Service %s deleted successfully.\n",
618 WIN32_Service_name);
619
620 CloseServiceHandle(schService);
621 }
622
623 CloseServiceHandle(schSCManager);
624 }
625 }
626
627 void
628 WIN32_SetServiceCommandLine()
629 {
630 if (!WIN32_Service_name)
631 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
632
633 strcat(REGKEY, WIN32_Service_name);
634
635 keys[4] = WIN32_Service_name;
636
637 /* Now store the Service Command Line in the registry */
638 WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1);
639 }
640
641 void
642 WIN32_InstallService()
643 {
644 SC_HANDLE schService;
645 SC_HANDLE schSCManager;
646 char ServicePath[512];
647 char szPath[512];
648 int lenpath;
649
650 if (!WIN32_Service_name)
651 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
652
653 strcat(REGKEY, WIN32_Service_name);
654
655 keys[4] = WIN32_Service_name;
656
657 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
658 fprintf(stderr, "Can't get executable path\n");
659 exit(1);
660 }
661
662 snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name);
663 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
664 NULL, /* database (NULL == default) */
665 SC_MANAGER_ALL_ACCESS /* access required */
666 );
667
668 if (!schSCManager) {
669 fprintf(stderr, "OpenSCManager failed\n");
670 exit(1);
671 } else {
672 schService = CreateService(schSCManager, /* SCManager database */
673 WIN32_Service_name, /* name of service */
674 WIN32_Service_name, /* name to display */
675 SERVICE_ALL_ACCESS, /* desired access */
676 SERVICE_WIN32_OWN_PROCESS, /* service type */
677 SERVICE_AUTO_START, /* start type */
678 SERVICE_ERROR_NORMAL, /* error control type */
679 (const char *) szPath, /* service's binary */
680 NULL, /* no load ordering group */
681 NULL, /* no tag identifier */
682 "Tcpip\0AFD\0", /* dependencies */
683 NULL, /* LocalSystem account */
684 NULL); /* no password */
685
686 if (schService) {
687 if ((WIN32_OS_version == _WIN_OS_WIN2K) || (WIN32_OS_version == _WIN_OS_WINXP)
688 || (WIN32_OS_version == _WIN_OS_WINNET)) {
689 HMODULE ADVAPI32Handle;
690 PFChangeServiceConfig2 ChangeServiceConfig2;
691 DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION;
692
693 ADVAPI32Handle = GetModuleHandle("advapi32");
694 ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2);
695 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription);
696 dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS;
697 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions);
698 }
699
700 CloseServiceHandle(schService);
701 /* Now store the config file location in the registry */
702
703 if (!ConfigFile)
704 ConfigFile = xstrdup(DefaultConfigFile);
705
706 WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
707
708 printf("Squid Cache version %s for %s\n", version_string,
709 CONFIG_HOST_TYPE);
710
711 printf("installed successfully as %s Windows System Service.\n",
712 WIN32_Service_name);
713
714 printf
715 ("To run, start it from the Services Applet of Control Panel.\n");
716
717 printf("Don't forget to edit squid.conf before starting it.\n\n");
718 } else {
719 fprintf(stderr, "CreateService failed\n");
720 exit(1);
721 }
722
723 CloseServiceHandle(schSCManager);
724 }
725 }
726
727 void
728 WIN32_sendSignal(int WIN32_signal)
729 {
730 SERVICE_STATUS ssStatus;
731 DWORD fdwAccess, fdwControl;
732 SC_HANDLE schService;
733 SC_HANDLE schSCManager;
734
735 if (!WIN32_Service_name)
736 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
737
738 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
739 NULL, /* database (NULL == default) */
740 SC_MANAGER_ALL_ACCESS /* access required */
741 );
742
743 if (!schSCManager) {
744 fprintf(stderr, "OpenSCManager failed\n");
745 exit(1);
746 }
747
748 /* The required service object access depends on the control. */
749 switch (WIN32_signal) {
750
751 case 0: /* SIGNULL */
752 fdwAccess = SERVICE_INTERROGATE;
753 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
754 break;
755
756 case SIGUSR1:
757 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
758 fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
759 break;
760
761 case SIGUSR2:
762 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
763 fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
764 break;
765
766 case SIGHUP:
767 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
768 fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
769 break;
770
771 case SIGTERM:
772 fdwAccess = SERVICE_STOP;
773 fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
774 break;
775
776 case SIGINT:
777
778 case SIGKILL:
779 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
780 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
781 break;
782
783 default:
784 exit(1);
785 }
786
787 /* Open a handle to the service. */
788 schService = OpenService(schSCManager, /* SCManager database */
789 WIN32_Service_name, /* name of service */
790 fdwAccess); /* specify access */
791
792 if (schService == NULL) {
793 fprintf(stderr, "%s: ERROR: Could not open Service %s\n", appname,
794 WIN32_Service_name);
795 exit(1);
796 } else {
797 /* Send a control value to the service. */
798
799 if (!ControlService(schService, /* handle of service */
800 fdwControl, /* control value to send */
801 &ssStatus)) { /* address of status info */
802 fprintf(stderr, "%s: ERROR: Could not Control Service %s\n",
803 appname, WIN32_Service_name);
804 exit(1);
805 } else {
806 /* Print the service status. */
807 printf("\nStatus of %s Service:\n", WIN32_Service_name);
808 printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType);
809 printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState);
810 printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted);
811 printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode);
812 printf(" Service Specific Exit Code: %ld\n",
813 ssStatus.dwServiceSpecificExitCode);
814 printf(" Check Point: %ld\n", ssStatus.dwCheckPoint);
815 printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint);
816 }
817
818 CloseServiceHandle(schService);
819 }
820
821 CloseServiceHandle(schSCManager);
822 }
823
824 int main(int argc, char **argv)
825 {
826 SERVICE_TABLE_ENTRY DispatchTable[] = {
827 {NULL, SquidMain},
828 {NULL, NULL}
829 };
830 char *c;
831
832 if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)) {
833 WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE;
834 opt_no_daemon = 1;
835
836 if (!(c=strchr(argv[1],':'))) {
837 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
838 return 1;
839 }
840
841 WIN32_Service_name = xstrdup(c+1);
842 DispatchTable[0].lpServiceName=WIN32_Service_name;
843 strcat(REGKEY, WIN32_Service_name);
844 keys[4] = WIN32_Service_name;
845
846 if (!StartServiceCtrlDispatcher(DispatchTable)) {
847 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n",
848 GetLastError());
849 return 1;
850 }
851 } else {
852 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
853 SquidMain(argc, argv);
854 }
855
856 return 0;
857 }
858
859 #endif /* USE_WIN32_SERVICE */
860
861 #endif /* WIN32_C */