"Fossies" - the Fresh Open Source Software Archive 
Member "zebedee-2.5.3/service.c" (12 Apr 2001, 13750 Bytes) of package /linux/privat/old/zebedee-2.5.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "service.c" see the
Fossies "Dox" file reference documentation.
1 /*
2 ** This file is part of "zebedee"
3 **
4 ** Copyright 1999 by Neil Winton. All rights reserved.
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** $Id: service.c,v 1.1.1.1 2001/04/12 18:07:12 ndwinton Exp $
21 **
22 ** $Log: service.c,v $
23 ** Revision 1.1.1.1 2001/04/12 18:07:12 ndwinton
24 ** Imported source of Zebedee 2.2.1
25 **
26 ** Revision 1.2 2000/01/08 21:35:22 nwinton
27 ** Version 1.3.0
28 **
29 ** Revision 1.1 1999/09/24 20:20:58 nwinton
30 ** Cleanup of compiler warnings
31 **
32 ** Revision 1.0 1999/09/18 21:35:06 nwinton
33 ** Initial revision
34 **
35 */
36
37 #include <windows.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <process.h>
41
42 char *service_c_rcsid = "$Id: service.c,v 1.1.1.1 2001/04/12 18:07:12 ndwinton Exp $";
43
44 extern void message(unsigned short, int, char *, ...);
45
46 #define MAX_BUF_SIZE 2048
47
48 HANDLE SvcFinishEvent = NULL;
49 SERVICE_STATUS SvcStatus; /* Current status of service */
50 SERVICE_STATUS_HANDLE SvcStatusHandle;
51 DWORD SvcError;
52 HANDLE SvcThreadHandle = NULL;
53 char *SvcName = NULL;
54 VOID (*SvcFunction)(VOID *) = NULL;
55 VOID *SvcArg = NULL;
56
57 DWORD svcPlatform(void);
58 VOID svcRun(char *name, VOID (*function)(VOID *), VOID *arg);
59 VOID svcRun9X(char *name);
60 VOID svcRunNT(char *name);
61 VOID svcMain(DWORD argc, LPTSTR *argv);
62 VOID svcControl(DWORD ctrlCode);
63 BOOL svcReport(DWORD currentState, DWORD exitCode, DWORD checkPoint,
64 DWORD waitHint);
65 VOID svcStop(LPTSTR msg);
66 int svcInstall(char *name, char *configFile);
67 int svcInstall9X(char *name, char *configFile);
68 int svcInstallNT(char *name, char *configFile);
69 int svcRemove(char *name);
70 int svcRemove9X(char *name);
71 int svcRemoveNT(char *name);
72
73
74 DWORD
75 svcPlatform(void)
76 {
77 OSVERSIONINFO info;
78
79 info.dwOSVersionInfoSize = sizeof(info);
80 if (!GetVersionEx(&info))
81 {
82 message(0, 0, "can't get OS version info");
83 return 0;
84 }
85 return info.dwPlatformId;
86 }
87
88 VOID
89 svcRun(char *name, VOID (*function)(VOID *), VOID *arg)
90 {
91 DWORD platform = svcPlatform();
92
93 SvcName = name;
94 SvcFunction = function;
95 SvcArg = arg;
96
97 switch (platform)
98 {
99 case VER_PLATFORM_WIN32_WINDOWS:
100 svcRun9X(name);
101 break;
102
103 case VER_PLATFORM_WIN32_NT:
104 svcRunNT(name);
105 break;
106
107 default:
108 message(0, 0, "unsupported OS platform (type %d)", platform);
109 break;
110 }
111 }
112
113 VOID
114 svcRunNT(char *name)
115 {
116 SERVICE_TABLE_ENTRY dispatchTable[] = {
117 { TEXT(name), (LPSERVICE_MAIN_FUNCTION)svcMain },
118 { NULL, NULL }
119 };
120
121 if (!StartServiceCtrlDispatcher(dispatchTable))
122 {
123 svcStop("StartServiceCtrlDispatcher failed");
124 }
125 }
126
127 VOID
128 svcRun9X(char *name)
129 {
130 HINSTANCE kernelDll;
131 DWORD (*regFn)(void *, DWORD);
132
133
134 /* Obtain a handle to the kernel library */
135
136 if ((kernelDll = LoadLibrary("KERNEL32.DLL")) == NULL)
137 {
138 message(0, 0, "can't get handle to kernel library");
139 return;
140 }
141
142 /* Find the address of the RegisterServiceProcess function */
143
144 regFn = (DWORD (*)(void *, DWORD))GetProcAddress(kernelDll, "RegisterServiceProcess");
145 if (regFn == NULL)
146 {
147 message(0, 0, "can't get the address of RegisterServiceProcess()");
148 return;
149 }
150
151 /* Register this process with the OS as a service */
152
153 if ((*regFn)(NULL, 1 /* RSP_SIMPLE_SERVICE */) == 0)
154 {
155 message(0, 0, "failed to register service process");
156 exit(EXIT_FAILURE);
157 }
158
159 /* Run the main routine */
160
161 (*SvcFunction)(SvcArg);
162
163 /* Unregister the process */
164
165 if ((*regFn)(NULL, 0 /* RSP_UNREGISTER_SERVICE */) == 0)
166 {
167 message(0, 0, "failed to unregister service process");
168 exit(EXIT_FAILURE);
169 }
170
171 /* Free the kernel library */
172
173 FreeLibrary(kernelDll);
174
175 exit(EXIT_SUCCESS);
176 }
177
178 /*
179 ** svcMain
180 **
181 ** This function starts the service worker thread proper. It then waits
182 ** for the worker to terminate.
183 **
184 */
185
186 VOID
187 svcMain(DWORD argc, LPTSTR *argv)
188 {
189 DWORD wait;
190
191
192 /* Register the control handler */
193
194 SvcStatusHandle = RegisterServiceCtrlHandler(TEXT(SvcName),
195 (LPHANDLER_FUNCTION)svcControl);
196 if (!SvcStatusHandle)
197 {
198 message(0, 0, "failed to register service control handler");
199 goto finish;
200 }
201
202 /* Initialise static service status values */
203
204 SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
205 SvcStatus.dwServiceSpecificExitCode = 0;
206
207 /* Report to SCM */
208
209 if (!svcReport(SERVICE_START_PENDING, /* Service state */
210 NO_ERROR, /* Exit code */
211 1, /* Checkpoint number */
212 5000)) /* Wait hint -- 5 secs */
213 {
214 message(0, 0, "failed to report status to SCM");
215 goto finish;
216 }
217
218 /*
219 ** Create the "stop event" object. The arguments indicate a manually
220 ** reset event whose initial state is unset.
221 */
222
223 if ((SvcFinishEvent = CreateEvent(NULL, 1, 0, NULL)) == NULL)
224 {
225 goto finish;
226 }
227
228 /* Report next checkpoint to SCM */
229
230 if (!svcReport(SERVICE_START_PENDING, NO_ERROR, 2, 5000))
231 {
232 message(0, 0, "failed to report status to SCM");
233 goto finish;
234 }
235
236 /* Start the worker thread */
237
238 SvcThreadHandle = (HANDLE)_beginthread(SvcFunction, 65536, SvcArg);
239 if (!SvcThreadHandle)
240 {
241 message(0, 0, "failed to create worker thread");
242 goto finish;
243 }
244
245 /* Report all systems GO! */
246
247 if (!svcReport(SERVICE_RUNNING, NO_ERROR, 0, 0))
248 {
249 message(0, 0, "failed to report status to SCM");
250 goto finish;
251 }
252
253 /* Wait until SvcFinishEvent is set */
254
255 wait = WaitForSingleObject(SvcFinishEvent, INFINITE);
256
257 finish:
258 if (SvcFinishEvent != NULL)
259 {
260 CloseHandle(SvcFinishEvent);
261 }
262
263 /* Report to SCM if possible */
264
265 if (SvcStatusHandle != 0)
266 {
267 svcReport(SERVICE_STOPPED, SvcError, 0, 0);
268 }
269
270 return;
271 }
272
273 /*
274 ** svcControl
275 **
276 ** Handle SCM service control requests
277 */
278
279 VOID
280 svcControl(DWORD code)
281 {
282 DWORD state = SERVICE_RUNNING;
283
284
285 switch(code)
286 {
287 case SERVICE_CONTROL_PAUSE:
288 if (SvcStatus.dwCurrentState == SERVICE_RUNNING)
289 {
290 SuspendThread(SvcThreadHandle);
291 state = SERVICE_PAUSED;
292 }
293 break;
294
295 case SERVICE_CONTROL_CONTINUE:
296 if (SvcStatus.dwCurrentState == SERVICE_PAUSED)
297 {
298 ResumeThread(SvcThreadHandle);
299 state = SERVICE_RUNNING;
300 }
301 break;
302
303 case SERVICE_CONTROL_STOP:
304 state = SERVICE_STOP_PENDING;
305 svcReport(SERVICE_STOP_PENDING, NO_ERROR, 1, 5000);
306 SetEvent(SvcFinishEvent);
307 return;
308
309 case SERVICE_CONTROL_INTERROGATE:
310 break;
311
312 default:
313 break;
314 }
315
316 svcReport(state, NO_ERROR, 0, 0);
317 }
318
319 /*
320 ** svcReport
321 **
322 ** Update the SCM with the current state of the service.
323 */
324
325 BOOL
326 svcReport(DWORD currentState, DWORD exitCode, DWORD checkPoint, DWORD waitHint)
327 {
328 BOOL result;
329
330 /* Disable control requests while starting */
331
332 if (currentState == SERVICE_START_PENDING)
333 {
334 SvcStatus.dwControlsAccepted = 0;
335 }
336 else
337 {
338 SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
339 SERVICE_ACCEPT_PAUSE_CONTINUE;
340 }
341
342 SvcStatus.dwCurrentState = currentState;
343 SvcStatus.dwWin32ExitCode = exitCode;
344 SvcStatus.dwCheckPoint = checkPoint;
345 SvcStatus.dwWaitHint = waitHint;
346
347 /* Make the report */
348
349 if (!(result = SetServiceStatus(SvcStatusHandle, &SvcStatus)))
350 {
351 /* If there is an error then bail out */
352 svcStop("SetServiceStatus failed!");
353 }
354
355 return result;
356 }
357
358 /*
359 ** svcStop
360 **
361 ** Report an error and stop the service
362 */
363
364 VOID
365 svcStop(LPTSTR msg)
366 {
367 SvcError = GetLastError();
368
369 message(0, 0, "failed in Win32 service routines: code %#0x", SvcError);
370
371 /* Signal the main routine to finish */
372
373 SetEvent(SvcFinishEvent);
374 }
375
376 int
377 svcInstall(char *name, char *configFile)
378 {
379 const char *runArg = "-Srun";
380 char path[MAX_BUF_SIZE];
381 char cmd[MAX_BUF_SIZE];
382 const char *flag = "-f";
383 const char *quote = "\"";
384 DWORD platform = svcPlatform();
385
386
387 if (configFile == NULL)
388 {
389 flag = "";
390 quote = "";
391 configFile = "";
392 }
393
394 /*
395 ** Get the filename of the running executable. We need to leave
396 ** space in the buffer for additional arguments, whitespace and
397 ** quotes ...
398 */
399
400 if (GetModuleFileName(NULL, path,
401 MAX_BUF_SIZE - (strlen(configFile) + 20)) == 0)
402 {
403 message(0, 0, "can't get executable path");
404 return EXIT_FAILURE;
405 }
406
407 /*
408 ** Build the command string. If a config file was specified
409 ** this will be of the form:
410 **
411 ** "program path" -f "config file" -Srun
412 */
413
414 sprintf(cmd, "\"%s\" %s %s%s%s %s", path,
415 flag, quote, configFile, quote, runArg);
416
417 switch (platform)
418 {
419 case VER_PLATFORM_WIN32_WINDOWS:
420 return svcInstall9X(name, cmd);
421 break;
422
423 case VER_PLATFORM_WIN32_NT:
424 return svcInstallNT(name, cmd);
425 break;
426
427 default:
428 message(0, 0, "unsupported OS platform (type %d)", platform);
429 break;
430 }
431 return EXIT_FAILURE;
432 }
433
434 int
435 svcInstallNT(char *name, char *cmd)
436 {
437 SC_HANDLE svcHandle;
438 SC_HANDLE scmHandle;
439
440
441 /* Open the local SCM database */
442
443 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL)
444 {
445 message(0, 0, "can't open SCM database");
446 return EXIT_FAILURE;
447 }
448
449 /* Now create the service entry */
450
451 svcHandle = CreateService(scmHandle, /* SCM database handle */
452 name, /* Name of service */
453 name, /* Display name */
454 SERVICE_ALL_ACCESS, /* Desired access */
455 SERVICE_WIN32_OWN_PROCESS,/* Run in own process */
456 SERVICE_AUTO_START, /* Start during boot */
457 SERVICE_ERROR_NORMAL, /* Show message but continue boot */
458 cmd, /* Program plus arguments */
459 NULL, /* No load ordering group */
460 NULL, /* No tag identifier */
461 NULL, /* No dependencies */
462 NULL, /* Use LocalSystem account */
463 NULL); /* No password */
464 CloseServiceHandle(scmHandle);
465
466 if (svcHandle == NULL)
467 {
468 message(0, 0, "can't create service");
469 return EXIT_FAILURE;
470 }
471
472 CloseServiceHandle(svcHandle);
473
474 message(1, 0, "%s service installed to run '%s'", name, cmd);
475
476 return EXIT_SUCCESS;
477 }
478
479 int
480 svcInstall9X(char *name, char *cmd)
481 {
482 HKEY runKey;
483
484
485 /* Open RunServices registry key */
486
487 if (RegCreateKey(HKEY_LOCAL_MACHINE,
488 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
489 &runKey) != ERROR_SUCCESS)
490 {
491 message(0, 0, "can't locate registry key");
492 return EXIT_FAILURE;
493 }
494
495 /* Add value for this service */
496
497 if (RegSetValueEx(runKey, name, 0, REG_SZ, cmd, strlen(cmd) + 1) != ERROR_SUCCESS)
498 {
499 RegCloseKey(runKey);
500 message(0, 0, "failed to add value to registry");
501 return EXIT_FAILURE;
502 }
503
504 RegCloseKey(runKey);
505
506 message(1, 0, "%s service installed to run '%s'", name, cmd);
507
508 return EXIT_SUCCESS;
509 }
510
511 int
512 svcRemove(char *name)
513 {
514 DWORD platform = svcPlatform();
515
516
517 switch (platform)
518 {
519 case VER_PLATFORM_WIN32_WINDOWS:
520 return svcRemove9X(name);
521 break;
522
523 case VER_PLATFORM_WIN32_NT:
524 return svcRemoveNT(name);
525 break;
526
527 default:
528 message(0, 0, "unsupported OS platform (type %d)", platform);
529 break;
530 }
531
532 return EXIT_FAILURE;
533 }
534
535 int
536 svcRemoveNT(char *name)
537 {
538 SC_HANDLE svcHandle;
539 SC_HANDLE scmHandle;
540 SERVICE_STATUS status;
541 int retStatus = EXIT_SUCCESS;
542
543
544 /* Open the SCM */
545
546 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL)
547 {
548 svcHandle = OpenService(scmHandle, name, SERVICE_ALL_ACCESS);
549
550 if (svcHandle != NULL)
551 {
552 /* Try to stop the service */
553
554 if (ControlService(svcHandle, SERVICE_CONTROL_STOP, &status))
555 {
556 while (QueryServiceStatus(svcHandle, &status))
557 {
558 if (status.dwCurrentState == SERVICE_STOP_PENDING)
559 {
560 Sleep(1000);
561 }
562 else
563 {
564 break;
565 }
566 }
567
568 if (status.dwCurrentState != SERVICE_STOPPED)
569 {
570 message(0, 0, "failed to stop the '%s' service", name);
571 retStatus = EXIT_FAILURE;
572 }
573 }
574
575 /* Now remove the service from the SCM */
576
577 if (DeleteService(svcHandle))
578 {
579 message(1, 0, "successfully removed the '%s' service", name);
580 }
581 else
582 {
583 message(0, 0, "failed to remove the '%s' service", name);
584 retStatus = EXIT_FAILURE;
585 }
586
587 CloseServiceHandle(svcHandle);
588 }
589 else
590 {
591 message(0, 0, "can't find the '%s' service", name);
592 retStatus = EXIT_FAILURE;
593 }
594
595 CloseServiceHandle(scmHandle);
596 }
597 else
598 {
599 message(0, 0, "can't contact Service Control Manager");
600 retStatus = EXIT_FAILURE;
601 }
602
603 return retStatus;
604 }
605
606
607 int
608 svcRemove9X(char *name)
609 {
610 HKEY runKey;
611 int status = EXIT_SUCCESS;
612
613
614 /* Locate the RunServices registry entry */
615
616 if (RegOpenKey(HKEY_LOCAL_MACHINE,
617 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
618 &runKey) != ERROR_SUCCESS)
619 {
620 message(0, 0, "can't find the RunServices registry key");
621 status = EXIT_FAILURE;
622 }
623 else
624 {
625 /* Delete the key value for our service */
626
627 if (RegDeleteValue(runKey, name) != ERROR_SUCCESS)
628 {
629 message(0, 0, "failed to delete registry RunServices entry for '%s'", name);
630 status = EXIT_FAILURE;
631 }
632 else
633 {
634 message(1, 0, "successfully removed the '%s' service", name);
635 }
636
637 RegCloseKey(runKey);
638 }
639
640 return status;
641 }