]> git.ipfire.org Git - thirdparty/squid.git/blob - src/win32.cc
fix compiling on cygwin without the win32 service enabled - bug #731
[thirdparty/squid.git] / src / win32.cc
1
2 /*
3 * $Id: win32.cc,v 1.10 2003/08/03 21:02:41 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 (!Squid_Aborting) {
377 svcStatus.dwCurrentState = SERVICE_STOPPED;
378 SetServiceStatus(svcHandle, &svcStatus);
379 }
380
381 #endif
382
383 _exit(0);
384 }
385
386 #if USE_WIN32_SERVICE
387 int WIN32_Subsystem_Init(int * argc, char *** argv)
388 #else
389 int
390 WIN32_Subsystem_Init()
391 #endif
392 {
393 WIN32_OS_version = GetOSVersion();
394
395 if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S))
396 return 1;
397
398 if (atexit(WIN32_Exit) != 0)
399 return 1;
400
401 #if USE_WIN32_SERVICE
402
403 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE)
404 {
405 char path[512];
406 HKEY hndKey;
407
408 if (signal(SIGABRT, WIN32_Abort) == SIG_ERR)
409 return 1;
410
411 /* Register the service Handler function */
412 svcHandle =
413 RegisterServiceCtrlHandler(WIN32_Service_name,
414 WIN32_svcHandler);
415
416 if (svcHandle == 0)
417 return 1;
418
419 /* Set Process work dir to directory cointaining squid.exe */
420 GetModuleFileName(NULL, path, 512);
421
422 WIN32_module_name=xstrdup(path);
423
424 path[strlen(path) - 10] = '\0';
425
426 if (SetCurrentDirectory(path) == 0)
427 return 1;
428
429 safe_free(ConfigFile);
430
431 /* get config file from Windows Registry */
432 if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY, &hndKey) == ERROR_SUCCESS) {
433 DWORD Type = 0;
434 DWORD Size = 0;
435 LONG Result;
436 Result =
437 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
438
439 if (Result == ERROR_SUCCESS && Size) {
440 ConfigFile = static_cast<char *>(xmalloc(Size));
441 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile,
442 &Size);
443 } else
444 ConfigFile = xstrdup(DefaultConfigFile);
445
446 Size = 0;
447
448 Type = 0;
449
450 Result =
451 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
452
453 if (Result == ERROR_SUCCESS && Size) {
454 WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
455 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, (unsigned char *)WIN32_Service_Command_Line,
456 &Size);
457 } else
458 WIN32_Service_Command_Line = xstrdup("");
459
460 RegCloseKey(hndKey);
461 } else {
462 ConfigFile = xstrdup(DefaultConfigFile);
463 WIN32_Service_Command_Line = xstrdup("");
464 }
465
466 WIN32_build_argv(WIN32_Service_Command_Line);
467 *argc = WIN32_argc;
468 *argv = WIN32_argv;
469 /* Set Service Status to SERVICE_START_PENDING */
470 svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
471 svcStatus.dwCurrentState = SERVICE_START_PENDING;
472 svcStatus.dwControlsAccepted =
473 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
474 svcStatus.dwWin32ExitCode = 0;
475 svcStatus.dwServiceSpecificExitCode = 0;
476 svcStatus.dwCheckPoint = 0;
477 svcStatus.dwWaitHint = 10000;
478 SetServiceStatus(svcHandle, &svcStatus);
479
480 }
481
482 #endif
483
484 return 0;
485 }
486
487 #if USE_WIN32_SERVICE
488 void
489 WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
490 {
491 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
492 svcStatus.dwCheckPoint++;
493 svcStatus.dwWaitHint = WaitHint;
494 svcStatus.dwCurrentState = svcstate;
495 SetServiceStatus(svcHandle, &svcStatus);
496 }
497 }
498
499 VOID WINAPI
500 WIN32_svcHandler(DWORD Opcode)
501 {
502 DWORD status;
503
504 switch (Opcode) {
505
506 case _WIN_SQUID_SERVICE_CONTROL_STOP:
507
508 case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN:
509 /* Do whatever it takes to stop here. */
510 svcStatus.dwWin32ExitCode = 0;
511 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
512 svcStatus.dwCheckPoint = 0;
513 svcStatus.dwWaitHint = 10000;
514 shut_down(SIGTERM);
515
516 if (!SetServiceStatus(svcHandle, &svcStatus)) {
517 status = GetLastError();
518 debug(1, 1) ("SetServiceStatus error %ld\n", status);
519 }
520
521 debug(1, 1) ("Leaving Squid service\n");
522 return;
523
524 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE:
525 /* Fall through to send current status. */
526
527 if (!SetServiceStatus(svcHandle, &svcStatus)) {
528 status = GetLastError();
529 debug(1, 1) ("SetServiceStatus error %ld\n", status);
530 }
531
532 break;
533
534 case _WIN_SQUID_SERVICE_CONTROL_ROTATE:
535 rotate_logs(SIGUSR1);
536 break;
537
538 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE:
539 reconfigure(SIGHUP);
540 break;
541
542 case _WIN_SQUID_SERVICE_CONTROL_DEBUG:
543 sigusr2_handle(SIGUSR2);
544 break;
545
546 case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT:
547 /* Do whatever it takes to stop here. */
548 svcStatus.dwWin32ExitCode = 0;
549 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
550 svcStatus.dwCheckPoint = 0;
551 svcStatus.dwWaitHint = 10000;
552 shut_down(SIGINT);
553
554 if (!SetServiceStatus(svcHandle, &svcStatus)) {
555 status = GetLastError();
556 debug(1, 1) ("SetServiceStatus error %ld\n", status);
557 }
558
559 debug(1, 1) ("Leaving Squid service\n");
560 break;
561
562 default:
563 debug(1, 1) ("Unrecognized opcode %ld\n", Opcode);
564 }
565
566 return;
567 }
568
569 void
570 WIN32_RemoveService()
571 {
572 SC_HANDLE schService;
573 SC_HANDLE schSCManager;
574
575 if (!WIN32_Service_name)
576 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
577
578 strcat(REGKEY, WIN32_Service_name);
579
580 keys[4] = WIN32_Service_name;
581
582 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
583 NULL, /* database (NULL == default) */
584 SC_MANAGER_ALL_ACCESS /* access required */
585 );
586
587 if (!schSCManager)
588 fprintf(stderr, "OpenSCManager failed\n");
589 else {
590 schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS);
591
592 if (schService == NULL)
593 fprintf(stderr, "OpenService failed\n");
594
595 /* Could not open the service */
596 else {
597 /* try to stop the service */
598
599 if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
600 &svcStatus)) {
601 sleep(1);
602
603 while (QueryServiceStatus(schService, &svcStatus)) {
604 if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
605 sleep(1);
606 else
607 break;
608 }
609 }
610
611 /* now remove the service */
612 if (DeleteService(schService) == 0)
613 fprintf(stderr, "DeleteService failed.\n");
614 else
615 printf("Service %s deleted successfully.\n",
616 WIN32_Service_name);
617
618 CloseServiceHandle(schService);
619 }
620
621 CloseServiceHandle(schSCManager);
622 }
623 }
624
625 void
626 WIN32_SetServiceCommandLine()
627 {
628 if (!WIN32_Service_name)
629 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
630
631 strcat(REGKEY, WIN32_Service_name);
632
633 keys[4] = WIN32_Service_name;
634
635 /* Now store the Service Command Line in the registry */
636 WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1);
637 }
638
639 void
640 WIN32_InstallService()
641 {
642 SC_HANDLE schService;
643 SC_HANDLE schSCManager;
644 char ServicePath[512];
645 char szPath[512];
646 int lenpath;
647
648 if (!WIN32_Service_name)
649 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
650
651 strcat(REGKEY, WIN32_Service_name);
652
653 keys[4] = WIN32_Service_name;
654
655 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
656 fprintf(stderr, "Can't get executable path\n");
657 exit(1);
658 }
659
660 snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name);
661 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
662 NULL, /* database (NULL == default) */
663 SC_MANAGER_ALL_ACCESS /* access required */
664 );
665
666 if (!schSCManager) {
667 fprintf(stderr, "OpenSCManager failed\n");
668 exit(1);
669 } else {
670 schService = CreateService(schSCManager, /* SCManager database */
671 WIN32_Service_name, /* name of service */
672 WIN32_Service_name, /* name to display */
673 SERVICE_ALL_ACCESS, /* desired access */
674 SERVICE_WIN32_OWN_PROCESS, /* service type */
675 SERVICE_AUTO_START, /* start type */
676 SERVICE_ERROR_NORMAL, /* error control type */
677 (const char *) szPath, /* service's binary */
678 NULL, /* no load ordering group */
679 NULL, /* no tag identifier */
680 "Tcpip\0AFD\0", /* dependencies */
681 NULL, /* LocalSystem account */
682 NULL); /* no password */
683
684 if (schService) {
685 if ((WIN32_OS_version == _WIN_OS_WIN2K) || (WIN32_OS_version == _WIN_OS_WINXP)
686 || (WIN32_OS_version == _WIN_OS_WINNET)) {
687 HMODULE ADVAPI32Handle;
688 PFChangeServiceConfig2 ChangeServiceConfig2;
689 DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION;
690
691 ADVAPI32Handle = GetModuleHandle("advapi32");
692 ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2);
693 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription);
694 dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS;
695 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions);
696 }
697
698 CloseServiceHandle(schService);
699 /* Now store the config file location in the registry */
700
701 if (!ConfigFile)
702 ConfigFile = xstrdup(DefaultConfigFile);
703
704 WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
705
706 printf("Squid Cache version %s for %s\n", version_string,
707 CONFIG_HOST_TYPE);
708
709 printf("installed successfully as %s Windows System Service.\n",
710 WIN32_Service_name);
711
712 printf
713 ("To run, start it from the Services Applet of Control Panel.\n");
714
715 printf("Don't forget to edit squid.conf before starting it.\n\n");
716 } else {
717 fprintf(stderr, "CreateService failed\n");
718 exit(1);
719 }
720
721 CloseServiceHandle(schSCManager);
722 }
723 }
724
725 void
726 WIN32_sendSignal(int WIN32_signal)
727 {
728 SERVICE_STATUS ssStatus;
729 DWORD fdwAccess, fdwControl;
730 SC_HANDLE schService;
731 SC_HANDLE schSCManager;
732
733 if (!WIN32_Service_name)
734 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
735
736 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
737 NULL, /* database (NULL == default) */
738 SC_MANAGER_ALL_ACCESS /* access required */
739 );
740
741 if (!schSCManager) {
742 fprintf(stderr, "OpenSCManager failed\n");
743 exit(1);
744 }
745
746 /* The required service object access depends on the control. */
747 switch (WIN32_signal) {
748
749 case 0: /* SIGNULL */
750 fdwAccess = SERVICE_INTERROGATE;
751 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
752 break;
753
754 case SIGUSR1:
755 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
756 fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
757 break;
758
759 case SIGUSR2:
760 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
761 fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
762 break;
763
764 case SIGHUP:
765 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
766 fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
767 break;
768
769 case SIGTERM:
770 fdwAccess = SERVICE_STOP;
771 fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
772 break;
773
774 case SIGINT:
775
776 case SIGKILL:
777 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
778 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
779 break;
780
781 default:
782 exit(1);
783 }
784
785 /* Open a handle to the service. */
786 schService = OpenService(schSCManager, /* SCManager database */
787 WIN32_Service_name, /* name of service */
788 fdwAccess); /* specify access */
789
790 if (schService == NULL) {
791 fprintf(stderr, "%s: ERROR: Could not open Service %s\n", appname,
792 WIN32_Service_name);
793 exit(1);
794 } else {
795 /* Send a control value to the service. */
796
797 if (!ControlService(schService, /* handle of service */
798 fdwControl, /* control value to send */
799 &ssStatus)) { /* address of status info */
800 fprintf(stderr, "%s: ERROR: Could not Control Service %s\n",
801 appname, WIN32_Service_name);
802 exit(1);
803 } else {
804 /* Print the service status. */
805 printf("\nStatus of %s Service:\n", WIN32_Service_name);
806 printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType);
807 printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState);
808 printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted);
809 printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode);
810 printf(" Service Specific Exit Code: %ld\n",
811 ssStatus.dwServiceSpecificExitCode);
812 printf(" Check Point: %ld\n", ssStatus.dwCheckPoint);
813 printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint);
814 }
815
816 CloseServiceHandle(schService);
817 }
818
819 CloseServiceHandle(schSCManager);
820 }
821
822 int main(int argc, char **argv)
823 {
824 SERVICE_TABLE_ENTRY DispatchTable[] = {
825 {NULL, SquidMain},
826 {NULL, NULL}
827 };
828 char *c;
829
830 if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)) {
831 WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE;
832 opt_no_daemon = 1;
833
834 if (!(c=strchr(argv[1],':'))) {
835 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
836 return 1;
837 }
838
839 WIN32_Service_name = xstrdup(c+1);
840 DispatchTable[0].lpServiceName=WIN32_Service_name;
841 strcat(REGKEY, WIN32_Service_name);
842 keys[4] = WIN32_Service_name;
843
844 if (!StartServiceCtrlDispatcher(DispatchTable)) {
845 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n",
846 GetLastError());
847 return 1;
848 }
849 } else {
850 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
851 SquidMain(argc, argv);
852 }
853
854 return 0;
855 }
856
857 #endif /* USE_WIN32_SERVICE */
858
859 #endif /* WIN32_C */