Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / libadmin / cfg / cfginternal.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #ifdef AFS_NT40_ENV
17 #include <windows.h>
18 #include <WINNT/afsreg.h>
19 #endif /* AFS_NT40_ENV */
20
21 #ifdef HAVE_MATH_H
22 # include <math.h>
23 #endif
24
25 #include <pthread.h>
26
27 #include <afs/afs_Admin.h>
28 #include <afs/afs_AdminErrors.h>
29 #include <afs/afs_bosAdmin.h>
30 #include <afs/afs_clientAdmin.h>
31
32 #include <afs/dirpath.h>
33
34 #include "cfginternal.h"
35 #include "../adminutil/afs_AdminInternal.h"
36
37
38 /*
39 * cfgutil_HostHandleValidate() -- validate a host configuration handle
40 *
41 * RETURN CODES: 1 success, 0 failure
42 */
43 int
44 cfgutil_HostHandleValidate(const cfg_host_p cfg_host, afs_status_p st)
45 {
46 int rc = 1;
47 afs_status_t tst = 0;
48
49 if (cfg_host == NULL) {
50 tst = ADMCFGHOSTHANDLENULL;
51
52 } else if (cfg_host->begin_magic != BEGIN_MAGIC
53 || cfg_host->end_magic != END_MAGIC) {
54 tst = ADMCFGHOSTHANDLEBADMAGIC;
55
56 } else if (cfg_host->is_valid == 0) {
57 tst = ADMCFGHOSTHANDLEINVALID;
58
59 } else if (cfg_host->hostName == NULL) {
60 tst = ADMCFGHOSTHANDLEHOSTNAMENULL;
61
62 } else if (cfg_host->cellHandle == NULL) {
63 tst = ADMCFGHOSTHANDLECELLHANDLENULL;
64
65 } else if (cfg_host->cellName == NULL) {
66 tst = ADMCFGHOSTHANDLECELLNAMENULL;
67 }
68
69 if (tst != 0) {
70 /* indicate failure */
71 rc = 0;
72 }
73 if (st != NULL) {
74 *st = tst;
75 }
76 return rc;
77 }
78
79
80 /*
81 * cfgutil_HostHandleBosInit() -- initialize bosserver handle in host
82 * configuration handle.
83 *
84 * RETURN CODES: 1 success, 0 failure
85 */
86 int
87 cfgutil_HostHandleBosInit(cfg_host_p cfg_host, afs_status_p st)
88 {
89 int rc = 1;
90 afs_status_t tst = 0;
91
92 if (pthread_mutex_lock(&cfg_host->mutex)) {
93 tst = ADMMUTEXLOCK;
94 } else {
95 if (cfg_host->bosHandle == NULL) {
96 /* initialize bosserver handle for host */
97 void *bosHandle;
98 afs_status_t tst2;
99
100 if (bos_ServerOpen
101 (cfg_host->cellHandle, cfg_host->hostName, &bosHandle,
102 &tst2)) {
103 cfg_host->bosHandle = bosHandle;
104 } else {
105 tst = tst2;
106 }
107 }
108 if (pthread_mutex_unlock(&cfg_host->mutex)) {
109 /* can only return one status; mutex failure is critical */
110 tst = ADMMUTEXUNLOCK;
111 }
112 }
113
114 if (tst != 0) {
115 /* indicate failure */
116 rc = 0;
117 }
118 if (st != NULL) {
119 *st = tst;
120 }
121 return rc;
122 }
123
124
125 /*
126 * cfgutil_HostHandleCellNameCompatible() -- determine if specified cell name
127 * is compatible with the cell name in the given cfg handle.
128 *
129 * RETURN CODES: 1 compatible, 0 not compatible
130 */
131 int
132 cfgutil_HostHandleCellNameCompatible(const cfg_host_p cfg_host,
133 const char *cellName)
134 {
135 int rc;
136
137 if (*cfg_host->cellName == '\0') {
138 /* null cell handle; any cell name compatible by definition */
139 rc = 1;
140 } else {
141 /* standard cell handle; compare cell names */
142 rc = (strcasecmp(cfg_host->cellName, cellName) == 0 ? 1 : 0);
143 }
144 return rc;
145 }
146
147
148 /*
149 * cfgutil_HostNameGetFull() -- return fully qualified version of specified
150 * host name.
151 *
152 * Note: fullHostName is presumed to be a buffer of size MAXHOSTCHARS.
153 *
154 * RETURN CODES: 1 success, 0 failure
155 */
156 int
157 cfgutil_HostNameGetFull(const char *hostName, char *fullHostName,
158 afs_status_p st)
159 {
160 int rc = 1;
161 afs_status_t tst = 0;
162
163 #ifdef AFS_NT40_ENV
164 /* Note: gethostbyname() allocs hostent on a per-thread basis */
165 struct hostent *hentryp;
166
167 if ((hentryp = gethostbyname(hostName)) == NULL) {
168 tst = ADMCFGCANTRESOLVEHOSTNAME;
169 } else {
170 size_t hostNameLen = strlen(hostName);
171 char *fqName = hentryp->h_name;
172
173 /* verify that canonical name is an expansion of name specified */
174 if (strncasecmp(fqName, hostName, hostNameLen) != 0
175 || fqName[hostNameLen] != '.') {
176 /* canonical name not a direct expansion; consider aliases */
177 int i;
178
179 for (i = 0; hentryp->h_aliases[i] != NULL; i++) {
180 char *aliasName = hentryp->h_aliases[i];
181 if (strncasecmp(aliasName, hostName, hostNameLen) == 0
182 && aliasName[hostNameLen] == '.') {
183 /* found a direct exapansion of specified name */
184 fqName = aliasName;
185 break;
186 }
187 }
188 }
189
190 if (strlen(fqName) > (MAXHOSTCHARS - 1)) {
191 tst = ADMCFGRESOLVEDHOSTNAMETOOLONG;
192 } else {
193 strcpy(fullHostName, fqName);
194
195 /* lower-case name for consistency */
196 _strlwr(fullHostName);
197 }
198 }
199 #else
200 /* function not yet implemented for Unix */
201 tst = ADMCFGNOTSUPPORTED;
202 #endif /* AFS_NT40_ENV */
203
204 if (tst != 0) {
205 /* indicate failure */
206 rc = 0;
207 }
208 if (st != NULL) {
209 *st = tst;
210 }
211 return rc;
212 }
213
214
215 /*
216 * cfgutil_HostNameIsAlias() -- determine if specified host names
217 * are aliases (functionally equivalent).
218 *
219 * RETURN CODES: 1 success, 0 failure
220 */
221 int
222 cfgutil_HostNameIsAlias(const char *hostName1, const char *hostName2,
223 short *isAlias, afs_status_p st)
224 {
225 int rc = 1;
226 afs_status_t tst2, tst = 0;
227 int addrCount1, addrCount2;
228 afs_int32 *addrList1 = NULL, *addrList2 = NULL;
229
230 /* get all addrs for first host */
231
232 if (!cfgutil_HostAddressFetchAll
233 (hostName1, &addrCount1, &addrList1, &tst2)) {
234 tst = tst2;
235 }
236
237 /* get all addrs for second host */
238
239 if (tst == 0) {
240 if (!cfgutil_HostAddressFetchAll
241 (hostName2, &addrCount2, &addrList2, &tst2)) {
242 tst = tst2;
243 if (addrList1) {
244 free(addrList1);
245 addrList1 = NULL;
246 }
247 }
248 }
249
250 /* compare lists looking for a match */
251
252 if (tst == 0) {
253 int i, j;
254
255 *isAlias = 0;
256
257 for (i = 0; i < addrCount1; i++) {
258 for (j = 0; j < addrCount2; j++) {
259 if (addrList1[i] == addrList2[j]) {
260 *isAlias = 1;
261 break;
262 }
263 }
264 }
265 if (addrList1) {
266 free(addrList1);
267 addrList1 = NULL;
268 }
269 if (addrList2) {
270 free(addrList2);
271 addrList2 = NULL;
272 }
273 }
274
275 if (tst != 0) {
276 /* indicate failure */
277 rc = 0;
278 }
279 if (st != NULL) {
280 *st = tst;
281 }
282 return rc;
283 }
284
285
286 /*
287 * cfgutil_HostNameIsLocal() -- determine if the specified host name is
288 * equivalent to (is an alias for) the standard host name for the
289 * machine on which this process is running.
290 *
291 * RETURN CODES: 1 success, 0 failure
292 */
293 int
294 cfgutil_HostNameIsLocal(const char *hostName, short *isLocal, afs_status_p st)
295 {
296 int rc = 1;
297 afs_status_t tst2, tst = 0;
298 char localName[MAXHOSTCHARS];
299
300 if (gethostname(localName, MAXHOSTCHARS)) {
301 /* failed to lookup local name */
302 tst = ADMCANTGETLOCALNAME;
303 } else if (!cfgutil_HostNameIsAlias(hostName, localName, isLocal, &tst2)) {
304 tst = tst2;
305 }
306
307 if (tst != 0) {
308 /* indicate failure */
309 rc = 0;
310 }
311 if (st != NULL) {
312 *st = tst;
313 }
314 return rc;
315 }
316
317
318 /*
319 * cfgutil_HostNameGetCellServDbAlias() -- Get alias for given host name
320 * as listed in the server CellServDB on the specified host. If no
321 * alias is found then hostNameAlias is set to the empty string.
322 *
323 * Note: hostNameAlias is presumed to be a buffer of size MAXHOSTCHARS.
324 *
325 * RETURN CODES: 1 success, 0 failure
326 */
327 int
328 cfgutil_HostNameGetCellServDbAlias(const char *fsDbHost, const char *hostName,
329 char *hostNameAlias, afs_status_p st)
330 {
331 int rc = 1;
332 afs_status_t tst2, tst = 0;
333 void *cellHandle;
334 void *bosHandle;
335
336 if (!afsclient_NullCellOpen(&cellHandle, &tst2)) {
337 tst = tst2;
338 } else {
339 if (!bos_ServerOpen(cellHandle, fsDbHost, &bosHandle, &tst2)) {
340 tst = tst2;
341 } else {
342 void *dbIter;
343
344 if (!bos_HostGetBegin(bosHandle, &dbIter, &tst2)) {
345 tst = tst2;
346 } else {
347 short dbhostDone = 0;
348 short dbhostFound = 0;
349
350 while (!dbhostDone) {
351 short isAlias;
352
353 if (!bos_HostGetNext(dbIter, hostNameAlias, &tst2)) {
354 /* no more entries (or failure) */
355 if (tst2 != ADMITERATORDONE) {
356 tst = tst2;
357 }
358 dbhostDone = 1;
359
360 } else
361 if (!cfgutil_HostNameIsAlias
362 (hostName, hostNameAlias, &isAlias, &tst2)) {
363 tst = tst2;
364 dbhostDone = 1;
365
366 } else if (isAlias) {
367 dbhostFound = 1;
368 dbhostDone = 1;
369 }
370 }
371
372 if (!dbhostFound) {
373 *hostNameAlias = '\0';
374 }
375
376 if (!bos_HostGetDone(dbIter, &tst2)) {
377 tst = tst2;
378 }
379 }
380
381 if (!bos_ServerClose(bosHandle, &tst2)) {
382 tst = tst2;
383 }
384 }
385
386 if (!afsclient_CellClose(cellHandle, &tst2)) {
387 tst = tst2;
388 }
389 }
390
391 if (tst != 0) {
392 /* indicate failure */
393 rc = 0;
394 }
395 if (st != NULL) {
396 *st = tst;
397 }
398 return rc;
399 }
400
401
402 /*
403 * cfgutil_HostNameGetAddressString() -- Get IP address for specified host in
404 * in the canonical string form.
405 *
406 * Returns pointer to a per-thread buffer; do not deallocate.
407 */
408 int
409 cfgutil_HostNameGetAddressString(const char *hostName, const char **hostAddr,
410 afs_status_p st)
411 {
412 int rc = 1;
413 afs_status_t tst2, tst = 0;
414 int addrCount;
415 afs_int32 *addrList = NULL;
416
417 /* get address list for host */
418
419 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
420 tst = tst2;
421 }
422
423 /* convert first (canonical) address to string */
424
425 if (tst == 0) {
426 struct in_addr ina;
427 char *inaString;
428
429 ina.s_addr = htonl(addrList[0]);
430 if ((inaString = inet_ntoa(ina)) == NULL) {
431 /* should never happen */
432 tst = ADMCFGCANTRESOLVEHOSTNAME;
433 } else {
434 *hostAddr = inaString;
435 }
436 if (addrList) {
437 free(addrList);
438 addrList = NULL;
439 }
440 }
441
442 if (tst != 0) {
443 /* indicate failure */
444 rc = 0;
445 }
446 if (st != NULL) {
447 *st = tst;
448 }
449 return rc;
450 }
451
452
453 /*
454 * cfgutil_HostAddressFetchAll() -- get allocated list of all known
455 * addresses for specified host.
456 *
457 * Note: upon success, *addrList is an address array in host byte order.
458 *
459 * RETURN CODES: 1 success, 0 failure
460 */
461 int
462 cfgutil_HostAddressFetchAll(const char *hostName, int *addrCount,
463 afs_int32 ** addrList, afs_status_p st)
464 {
465 int rc = 1;
466 afs_status_t tst = 0;
467 int aCount = 0;
468 afs_int32 *aList = NULL;
469
470 #ifdef AFS_NT40_ENV
471 /* Note: gethostbyname() allocs hostent on a per-thread basis */
472 struct hostent *hentryp;
473
474 if ((hentryp = gethostbyname(hostName)) == NULL) {
475 tst = ADMCFGCANTRESOLVEHOSTNAME;
476 } else {
477 int i;
478
479 /* assuming IPv4 addrs returned */
480 for (i = 0; hentryp->h_addr_list[i] != NULL; i++);
481 aCount = i;
482
483 if ((aList = malloc(aCount * sizeof(afs_int32))) == NULL) {
484 tst = ADMNOMEM;
485 } else {
486 for (i = 0; i < aCount; i++) {
487 afs_int32 hostAddr;
488 memcpy((void *)&hostAddr, (void *)hentryp->h_addr_list[i],
489 sizeof(afs_int32));
490 aList[i] = ntohl(hostAddr);
491 }
492 }
493 }
494 #else
495 /* function not yet implemented for Unix */
496 tst = ADMCFGNOTSUPPORTED;
497 #endif /* AFS_NT40_ENV */
498
499 if (tst == 0) {
500 /* return results */
501 *addrCount = aCount;
502 *addrList = aList;
503 } else {
504 /* indicate failure */
505 rc = 0;
506 }
507 if (st != NULL) {
508 *st = tst;
509 }
510 return rc;
511 }
512
513
514 /*
515 * cfgutil_HostAddressIsValid() -- determine if address is a valid address
516 * for the named host.
517 *
518 * Note: hostAddr must be specified in host byte order
519 *
520 * RETURN CODES: 1 success, 0 failure
521 */
522 int
523 cfgutil_HostAddressIsValid(const char *hostName, int hostAddr, short *isValid,
524 afs_status_p st)
525 {
526 int rc = 1;
527 afs_status_t tst2, tst = 0;
528 int addrCount;
529 afs_int32 *addrList = NULL;
530
531 *isValid = 0;
532
533 /* get all addrs for host */
534
535 if (!cfgutil_HostAddressFetchAll(hostName, &addrCount, &addrList, &tst2)) {
536 tst = tst2;
537 }
538
539 /* search list looking for match */
540
541 if (tst == 0) {
542 int i;
543
544 for (i = 0; i < addrCount; i++) {
545 if (addrList[i] == hostAddr) {
546 *isValid = 1;
547 break;
548 }
549 }
550 if (addrList) {
551 free(addrList);
552 addrList = NULL;
553 }
554 }
555
556 if (tst != 0) {
557 /* indicate failure */
558 rc = 0;
559 }
560 if (st != NULL) {
561 *st = tst;
562 }
563 return rc;
564 }
565
566
567 /*
568 * cfgutil_CleanDirectory() -- remove all files from specified directory;
569 * function is NOT recursive.
570 *
571 * RETURN CODES: 1 success, 0 failure
572 */
573 int
574 cfgutil_CleanDirectory(const char *dirName, afs_status_p st)
575 {
576 int rc = 1;
577 afs_status_t tst = 0;
578
579 DIR *dirp;
580 struct dirent *entryp;
581 char dirfile[MAXPATHLEN];
582
583 if ((dirp = opendir(dirName)) == NULL) {
584 /* cannot open directory */
585 if (errno == EACCES) {
586 tst = ADMNOPRIV;
587 }
588 /* otherwise assume directory does not exist, which is OK */
589 } else {
590 while ((entryp = readdir(dirp)) != NULL) {
591 /* remove file (except "." and "..") */
592 if (strcmp(entryp->d_name, ".") && strcmp(entryp->d_name, "..")) {
593 sprintf(dirfile, "%s/%s", dirName, entryp->d_name);
594 if (unlink(dirfile)) {
595 /* remove failed */
596 if (errno == EACCES) {
597 tst = ADMNOPRIV;
598 break;
599 }
600 /* otherwise assume file removed by someone else or
601 * that file is a directory, which is OK.
602 */
603 }
604 }
605 }
606
607 (void)closedir(dirp);
608 }
609
610 if (tst != 0) {
611 /* indicate failure */
612 rc = 0;
613 }
614 if (st != NULL) {
615 *st = tst;
616 }
617 return rc;
618 }
619
620
621 /*
622 * cfgutil_HostSetNoAuthFlag() -- set AFS server authentication flag on host
623 *
624 * RETURN CODES: 1 success, 0 failure (st indicates why)
625 */
626 int
627 cfgutil_HostSetNoAuthFlag(const cfg_host_p cfg_host, short noAuth,
628 afs_status_p st)
629 {
630 int rc = 1;
631 afs_status_t tst = 0;
632
633 /* remote configuration not yet supported in this function */
634
635 if (!cfg_host->is_local) {
636 tst = ADMCFGNOTSUPPORTED;
637 }
638
639 /* set mode; not using bosserver because may not have necessary creds */
640
641 if (tst == 0) {
642 if (noAuth) {
643 /* set no-authentication flag */
644 int fd = open(AFSDIR_SERVER_NOAUTH_FILEPATH,
645 O_CREAT | O_TRUNC | O_RDWR, 0666);
646
647 if (fd >= 0) {
648 close(fd);
649 } else {
650 if (errno == EACCES) {
651 tst = ADMNOPRIV;
652 } else {
653 tst = ADMCFGHOSTSETNOAUTHFAILED;
654 }
655 }
656 } else {
657 /* clear no-authentication flag */
658 if (unlink(AFSDIR_SERVER_NOAUTH_FILEPATH)) {
659 if (errno != ENOENT) {
660 if (errno == EACCES) {
661 tst = ADMNOPRIV;
662 } else {
663 tst = ADMCFGHOSTSETNOAUTHFAILED;
664 }
665 }
666 }
667 }
668 }
669
670 if (tst != 0) {
671 /* indicate failure */
672 rc = 0;
673 }
674 if (st != NULL) {
675 *st = tst;
676 }
677 return rc;
678 }
679
680
681 /*
682 * cfgutil_Sleep() -- put thread to sleep for specified number of seconds.
683 */
684 void
685 cfgutil_Sleep(unsigned sec)
686 {
687 #ifdef AFS_NT40_ENV
688 Sleep(sec * 1000);
689 #else
690 time_t timeStart = time(NULL);
691 struct timeval sleeptime;
692
693 sleeptime.tv_sec = sec;
694 sleeptime.tv_usec = 0;
695
696 while (1) {
697 if (select(0, 0, 0, 0, &sleeptime) == 0) {
698 /* timeout */
699 break;
700 } else {
701 /* returned for reason other than timeout */
702 double cumSec = difftime(time(NULL), timeStart);
703 double remSec = (double)sec - cumSec;
704
705 if (remSec <= 0.0) {
706 break;
707 }
708 sleeptime.tv_sec = ceil(remSec);
709 }
710 }
711 #endif
712 }
713
714
715
716 #ifdef AFS_NT40_ENV
717 /* Service control functions */
718
719 /* define generic service error codes */
720 #define CFGUTIL_SVC_NOPRIV 1 /* insufficient privilege */
721 #define CFGUTIL_SVC_BAD 2 /* service not properly configured */
722 #define CFGUTIL_SVC_NOTREADY 3 /* service not ready to accept command */
723 #define CFGUTIL_SVC_TIMEOUT 4 /* timed out waiting for stop/start */
724 #define CFGUTIL_SVC_STATUSUNK 5 /* service status cannot be determined */
725
726
727 /*
728 * ServiceCodeXlate() -- translate generic code to service-specific code
729 */
730 static afs_status_t
731 ServiceCodeXlate(LPCTSTR svcName, int code)
732 {
733 afs_status_t tst = ADMCFGNOTSUPPORTED;
734
735 if (!strcmp(svcName, AFSREG_CLT_SVC_NAME)) {
736 /* AFS client (CM) service code required */
737 switch (code) {
738 case CFGUTIL_SVC_NOPRIV:
739 tst = ADMNOPRIV;
740 break;
741 case CFGUTIL_SVC_BAD:
742 tst = ADMCFGCACHEMGRSERVICEBAD;
743 break;
744 case CFGUTIL_SVC_NOTREADY:
745 tst = ADMCFGCACHEMGRSERVICENOTREADY;
746 break;
747 case CFGUTIL_SVC_TIMEOUT:
748 tst = ADMCFGCACHEMGRSERVICETIMEOUT;
749 break;
750 default:
751 tst = ADMCFGCACHEMGRSERVICESTATUSUNK;
752 break;
753 }
754
755 } else if (!strcmp(svcName, AFSREG_SVR_SVC_NAME)) {
756 /* AFS BOS control service code required */
757 switch (code) {
758 case CFGUTIL_SVC_NOPRIV:
759 tst = ADMNOPRIV;
760 break;
761 case CFGUTIL_SVC_BAD:
762 tst = ADMCFGBOSSERVERCTLSERVICEBAD;
763 break;
764 case CFGUTIL_SVC_NOTREADY:
765 tst = ADMCFGBOSSERVERCTLSERVICENOTREADY;
766 break;
767 case CFGUTIL_SVC_TIMEOUT:
768 tst = ADMCFGBOSSERVERCTLSERVICETIMEOUT;
769 break;
770 default:
771 tst = ADMCFGBOSSERVERCTLSERVICESTATUSUNK;
772 break;
773 }
774 }
775 return tst;
776 }
777
778
779 /*
780 * cfgutil_WindowsServiceStart() -- Start a Windows service on local host.
781 *
782 * The value of timeout specifies the maximum time, in seconds, to wait
783 * for the service to be in the SERVICE_RUNNING state.
784 *
785 * If service was already started/starting then *wasRunning is true (1).
786 *
787 * RETURN CODES: 1 success, 0 failure (st indicates why)
788 */
789 int
790 cfgutil_WindowsServiceStart(LPCTSTR svcName, DWORD svcArgc, LPCTSTR * svcArgv,
791 unsigned timeout, short *wasRunning,
792 afs_status_p st)
793 {
794 int rc = 1;
795 afs_status_t tst = 0;
796 SC_HANDLE scmHandle, svcHandle;
797 DWORD svcAccess = (SERVICE_START | SERVICE_QUERY_STATUS);
798
799 *wasRunning = 0;
800
801 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
802 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
803 /* can't connect to SCM or can't open service */
804 DWORD status = GetLastError();
805
806 if (status == ERROR_ACCESS_DENIED) {
807 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
808 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
809 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
810 } else {
811 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
812 }
813
814 if (scmHandle != NULL) {
815 CloseServiceHandle(scmHandle);
816 }
817
818 } else {
819 /* service configured; attempt to start */
820 if (!StartService(svcHandle, svcArgc, svcArgv)) {
821 /* service start failed */
822 DWORD status = GetLastError();
823
824 if (status == ERROR_SERVICE_ALREADY_RUNNING) {
825 *wasRunning = 1;
826 } else {
827 if (status == ERROR_ACCESS_DENIED) {
828 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
829 } else if (status == ERROR_SERVICE_DATABASE_LOCKED
830 || status == ERROR_SERVICE_DISABLED
831 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
832 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
833 } else {
834 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
835 }
836 }
837 }
838
839 /* wait for service to be in SERVICE_RUNNING state */
840 if (tst == 0 && timeout > 0) {
841 SERVICE_STATUS svcStatus;
842 time_t timeStart = time(NULL);
843
844 while (1) {
845 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
846 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
847 break;
848 } else if (svcStatus.dwCurrentState == SERVICE_RUNNING) {
849 break;
850 } else if (difftime(time(NULL), timeStart) > timeout) {
851 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
852 break;
853 } else {
854 /* sleep a bit and check state again */
855 cfgutil_Sleep(5);
856 }
857 }
858
859 if (tst == 0) {
860 /* wait just a bit more because we're paranoid */
861 cfgutil_Sleep(1);
862 }
863 }
864
865 CloseServiceHandle(svcHandle);
866 CloseServiceHandle(scmHandle);
867 }
868
869 if (tst != 0) {
870 /* indicate failure */
871 rc = 0;
872 }
873 if (st != NULL) {
874 *st = tst;
875 }
876 return rc;
877 }
878
879
880 /*
881 * cfgutil_WindowsServiceStop() -- Stop a Windows service on local host.
882 *
883 * The value of timeout specifies the maximum time, in seconds, to wait
884 * for the service to be in the SERVICE_STOPPED state.
885 *
886 * If service was already stopped/stopping then *wasStopped is true (1).
887 *
888 * RETURN CODES: 1 success, 0 failure (st indicates why)
889 */
890 int
891 cfgutil_WindowsServiceStop(LPCTSTR svcName, unsigned timeout,
892 short *wasStopped, afs_status_p st)
893 {
894 int rc = 1;
895 afs_status_t tst = 0;
896 SC_HANDLE scmHandle, svcHandle;
897 DWORD svcAccess = (SERVICE_STOP | SERVICE_QUERY_STATUS);
898
899 *wasStopped = 0;
900
901 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
902 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
903 /* can't connect to SCM or can't open service */
904 DWORD status = GetLastError();
905
906 if (status == ERROR_ACCESS_DENIED) {
907 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
908 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
909 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
910 } else {
911 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
912 }
913
914 if (scmHandle != NULL) {
915 CloseServiceHandle(scmHandle);
916 }
917
918 } else {
919 /* service configured; attempt to stop */
920 SERVICE_STATUS svcStatus;
921
922 if (!ControlService(svcHandle, SERVICE_CONTROL_STOP, &svcStatus)) {
923 /* service stop failed */
924 DWORD status = GetLastError();
925
926 if (status == ERROR_SERVICE_NOT_ACTIVE) {
927 *wasStopped = 1;
928 } else {
929 if (status == ERROR_ACCESS_DENIED) {
930 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
931 } else if (status == ERROR_INVALID_SERVICE_CONTROL
932 || status == ERROR_SERVICE_CANNOT_ACCEPT_CTRL
933 || status == ERROR_SERVICE_REQUEST_TIMEOUT) {
934 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOTREADY);
935 } else {
936 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
937 }
938 }
939 }
940
941 /* wait for service to be in SERVICE_STOPPED state */
942 if (tst == 0 && timeout > 0) {
943 time_t timeStart = time(NULL);
944
945 while (1) {
946 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
947 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
948 break;
949 } else if (svcStatus.dwCurrentState == SERVICE_STOPPED) {
950 break;
951 } else if (difftime(time(NULL), timeStart) > timeout) {
952 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_TIMEOUT);
953 break;
954 } else {
955 /* sleep a bit and check state again */
956 cfgutil_Sleep(5);
957 }
958 }
959
960 if (tst == 0) {
961 /* wait just a bit more because we're paranoid */
962 cfgutil_Sleep(1);
963 }
964 }
965
966 CloseServiceHandle(svcHandle);
967 CloseServiceHandle(scmHandle);
968 }
969
970 if (tst != 0) {
971 /* indicate failure */
972 rc = 0;
973 }
974 if (st != NULL) {
975 *st = tst;
976 }
977 return rc;
978 }
979
980
981 /*
982 * cfgutil_WindowsServiceQuery() -- Query Windows service on local host.
983 *
984 * RETURN CODES: 1 success, 0 failure (st indicates why)
985 */
986 int
987 cfgutil_WindowsServiceQuery(LPCTSTR svcName, DWORD * svcState,
988 afs_status_p st)
989 {
990 int rc = 1;
991 afs_status_t tst = 0;
992 SC_HANDLE scmHandle, svcHandle;
993 DWORD svcAccess = SERVICE_QUERY_STATUS;
994
995 if ((scmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT)) == NULL
996 || (svcHandle = OpenService(scmHandle, svcName, svcAccess)) == NULL) {
997 /* can't connect to SCM or can't open service */
998 DWORD status = GetLastError();
999
1000 if (status == ERROR_ACCESS_DENIED) {
1001 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_NOPRIV);
1002 } else if (status == ERROR_SERVICE_DOES_NOT_EXIST) {
1003 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_BAD);
1004 } else {
1005 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1006 }
1007
1008 if (scmHandle != NULL) {
1009 CloseServiceHandle(scmHandle);
1010 }
1011
1012 } else {
1013 /* service configured; determine service state */
1014 SERVICE_STATUS svcStatus;
1015
1016 if (!QueryServiceStatus(svcHandle, &svcStatus)) {
1017 tst = ServiceCodeXlate(svcName, CFGUTIL_SVC_STATUSUNK);
1018 } else {
1019 *svcState = svcStatus.dwCurrentState;
1020 }
1021
1022 CloseServiceHandle(svcHandle);
1023 CloseServiceHandle(scmHandle);
1024 }
1025
1026 if (tst != 0) {
1027 /* indicate failure */
1028 rc = 0;
1029 }
1030 if (st != NULL) {
1031 *st = tst;
1032 }
1033 return rc;
1034 }
1035
1036 #endif /* AFS_NT40_ENV */