dfb40039eaffd587a9b6d520f8fc6ba9a3e70ee2
[openafs.git] / src / libadmin / cfg / cfgservers.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 /* This file implements configuration functions in the following categories:
11  *   cfg_BosServer*()    - configure the BOS server.
12  *   cfg_DbServers*()    - configure the database servers.
13  *   cfg_FileServer*()   - configure the fileserver.
14  *   cfg_UpdateServer*() - configure the update server.
15  *   cfg_UpdateClient*() - configure update clients.
16  */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #include <roken.h>
22
23 #include <afs/stds.h>
24
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <ctype.h>
31
32 #ifdef AFS_NT40_ENV
33 #include <windows.h>
34 #include <WINNT/afsreg.h>
35 #endif /* AFS_NT40_ENV */
36
37 #include <pthread.h>
38
39 #include <rx/rx.h>
40 #include <rx/rxstat.h>
41
42 #include <afs/afs_Admin.h>
43 #include <afs/afs_AdminErrors.h>
44 #include <afs/afs_bosAdmin.h>
45 #include <afs/afs_clientAdmin.h>
46 #include <afs/afs_utilAdmin.h>
47 #include <afs/afs_vosAdmin.h>
48
49 #include <afs/dirpath.h>
50 #include <afs/bnode.h>
51 #include <afs/cellconfig.h>
52 #include <afs/bubasics.h>
53 #include <rx/rx_null.h>
54
55 #define UBIK_INTERNALS          /* need "internal" symbols from ubik.h */
56 #include <ubik.h>
57
58 #include "cfginternal.h"
59 #include "afs_cfgAdmin.h"
60
61
62 /* Local declarations and definitions */
63
64 #define KASERVER_BOSNAME "kaserver"
65 #define KASERVER_EXEPATH  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/kaserver"
66
67 #define PTSERVER_BOSNAME "ptserver"
68 #define PTSERVER_EXEPATH  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/ptserver"
69
70 #define VLSERVER_BOSNAME "vlserver"
71 #define VLSERVER_EXEPATH  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/vlserver"
72
73 #define BUSERVER_BOSNAME "buserver"
74 #define BUSERVER_EXEPATH  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/buserver"
75
76 #define UPSERVER_BOSNAME "upserver"
77 #define UPSERVER_EXEPATH  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/upserver"
78
79 #define UPCLIENT_BOSNAME "upclient"
80 #define UPCLIENT_EXEPATH  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/upclient"
81
82 #define FILESERVER_BOSNAME "fs"
83 #define FILESERVER_EXEPATH  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/fileserver"
84 #define VOLSERVER_EXEPATH   AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/volserver"
85 #define SALVAGER_EXEPATH    AFSDIR_CANONICAL_SERVER_BIN_DIRPATH "/salvager"
86
87
88 static int
89   SimpleProcessStart(void *bosHandle, const char *instance,
90                      const char *executable, const char *args,
91                      afs_status_p st);
92
93 static int
94   FsProcessStart(void *bosHandle, const char *instance,
95                  const char *fileserverExe, const char *volserverExe,
96                  const char *salvagerExe, afs_status_p st);
97
98 static int
99   BosProcessDelete(void *bosHandle, const char *instance, afs_status_p st);
100
101 static void
102   UpdateCommandParse(char *cmdString, short *hasSysPathP, short *hasBinPathP);
103
104 static int
105   UbikQuorumCheck(cfg_host_p cfg_host, const char *dbInstance,
106                   short *hasQuorum, afs_status_p st);
107
108 static int
109   UbikVoteStatusFetch(int serverAddr, unsigned short serverPort,
110                       short *isSyncSite, short *isWriteReady,
111                       afs_status_p st);
112
113
114
115
116
117
118 /* ---------------- Exported constants ---------------- */
119
120 const char *cfg_kaserverBosName = KASERVER_BOSNAME;
121 const char *cfg_ptserverBosName = PTSERVER_BOSNAME;
122 const char *cfg_vlserverBosName = VLSERVER_BOSNAME;
123 const char *cfg_buserverBosName = BUSERVER_BOSNAME;
124 const char *cfg_fileserverBosName = FILESERVER_BOSNAME;
125 const char *cfg_upserverBosName = UPSERVER_BOSNAME;
126
127 const char *cfg_upclientBosNamePrefix = UPCLIENT_BOSNAME;
128 const char *cfg_upclientSysBosSuffix = "etc";
129 const char *cfg_upclientBinBosSuffix = "bin";
130
131
132
133 /* ---------------- Exported BOS Server functions ------------------ */
134
135
136 /*
137  * cfg_BosServerStart() -- Start the BOS server on host.
138  *
139  *     Timeout is the maximum time, in seconds, to wait for BOS to start.
140  */
141 int ADMINAPI
142 cfg_BosServerStart(void *hostHandle,    /* host config handle */
143                    short noAuth,        /* start in NoAuth mode */
144                    unsigned int timeout,        /* timeout (in seconds) */
145                    afs_status_p st)
146 {                               /* completion status */
147     int rc = 1;
148     afs_status_t tst2, tst = 0;
149     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
150     short wasRunning = 0;
151
152     /* validate parameters */
153
154     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
155         tst = tst2;
156     }
157
158     /* remote configuration not yet supported in this function */
159
160     if (tst == 0) {
161         if (!cfg_host->is_local) {
162             tst = ADMCFGNOTSUPPORTED;
163         }
164     }
165
166     /* start bosserver (if not already running) */
167
168 #ifdef AFS_NT40_ENV
169     /* Windows - bosserver is controlled via the BOS control service */
170     if (tst == 0) {
171         DWORD auxArgc;
172         LPCTSTR auxArgBuf[1], *auxArgv;
173
174         if (noAuth) {
175             auxArgc = 1;
176             auxArgv = auxArgBuf;
177             auxArgBuf[0] = "-noauth";
178         } else {
179             auxArgc = 0;
180             auxArgv = NULL;
181         }
182
183         if (!cfgutil_WindowsServiceStart
184             (AFSREG_SVR_SVC_NAME, auxArgc, auxArgv, timeout, &wasRunning,
185              &tst2)) {
186             /* failed to start BOS control service */
187             tst = tst2;
188         }
189     }
190 #else
191     if (tst == 0) {
192         /* function not yet implemented for Unix */
193         tst = ADMCFGNOTSUPPORTED;
194     }
195 #endif /* AFS_NT40_ENV */
196
197     /* put bosserver into requested auth mode if was already running */
198
199     if (tst == 0 && wasRunning) {
200         if (!cfgutil_HostSetNoAuthFlag(cfg_host, noAuth, &tst2)) {
201             tst = tst2;
202         }
203     }
204
205     if (tst != 0) {
206         /* indicate failure */
207         rc = 0;
208     }
209     if (st != NULL) {
210         *st = tst;
211     }
212     return rc;
213 }
214
215
216
217 /*
218  * cfg_BosServerStop() -- Stop the BOS server on host.
219  *
220  *     Timeout is the maximum time, in seconds, to wait for BOS to stop.
221  */
222 int ADMINAPI
223 cfg_BosServerStop(void *hostHandle,     /* host config handle */
224                   unsigned int timeout, /* timeout (in seconds) */
225                   afs_status_p st)
226 {                               /* completion status */
227     int rc = 1;
228     afs_status_t tst2, tst = 0;
229     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
230
231     /* validate parameters */
232
233     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
234         tst = tst2;
235     }
236
237     /* remote configuration not yet supported in this function */
238
239     if (tst == 0) {
240         if (!cfg_host->is_local) {
241             tst = ADMCFGNOTSUPPORTED;
242         }
243     }
244
245     /* stop the bosserver (if running) */
246
247 #ifdef AFS_NT40_ENV
248     /* Windows - bosserver is controlled via the BOS control service */
249     if (tst == 0) {
250         short wasStopped;
251
252         if (!cfgutil_WindowsServiceStop
253             (AFSREG_SVR_SVC_NAME, timeout, &wasStopped, &tst2)) {
254             /* failed to stop BOS control service */
255             tst = tst2;
256         }
257     }
258 #else
259     if (tst == 0) {
260         /* function not yet implemented for Unix */
261         tst = ADMCFGNOTSUPPORTED;
262     }
263 #endif /* AFS_NT40_ENV */
264
265     if (tst != 0) {
266         /* indicate failure */
267         rc = 0;
268     }
269     if (st != NULL) {
270         *st = tst;
271     }
272     return rc;
273 }
274
275
276 /*
277  * cfg_BosServerQueryStatus() -- Query status of BOS server on host.
278  *
279  *     The argument *isBosProcP is set to TRUE only if BOS processes
280  *     are currently executing (as opposed to configured but stopped).
281  */
282 int ADMINAPI
283 cfg_BosServerQueryStatus(void *hostHandle,      /* host config handle */
284                          short *isStartedP,     /* BOS server is started */
285                          short *isBosProcP,     /* BOS processes running */
286                          afs_status_p st)
287 {                               /* completion status */
288     int rc = 1;
289     afs_status_t tst2, tst = 0;
290     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
291
292     /* validate parameters and prepare host handle for bos functions */
293
294     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
295         tst = tst2;
296     } else if (isStartedP == NULL) {
297         tst = ADMCFGSTARTEDFLAGPNULL;
298     } else if (isBosProcP == NULL) {
299         tst = ADMCFGBOSSERVERPROCSFLAGPNULL;
300     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
301         tst = tst2;
302     }
303
304     /* remote configuration not yet supported in this function */
305
306     if (tst == 0) {
307         if (!cfg_host->is_local) {
308             tst = ADMCFGNOTSUPPORTED;
309         }
310     }
311
312     /* determine if bosserver is running */
313
314 #ifdef AFS_NT40_ENV
315     /* Windows - bosserver is controlled via the BOS control service */
316     if (tst == 0) {
317         DWORD svcState;
318
319         *isStartedP = *isBosProcP = 0;
320
321         if (!cfgutil_WindowsServiceQuery
322             (AFSREG_SVR_SVC_NAME, &svcState, &tst2)) {
323             tst = tst2;
324         } else if (svcState == SERVICE_RUNNING) {
325             *isStartedP = 1;
326         }
327     }
328 #else
329     if (tst == 0) {
330         /* function not yet implemented for Unix */
331         tst = ADMCFGNOTSUPPORTED;
332     }
333 #endif /* AFS_NT40_ENV */
334
335
336     /* query status of bos processes */
337
338     if (tst == 0 && *isStartedP) {
339         void *procIter;
340
341         *isBosProcP = 0;
342
343         if (!bos_ProcessNameGetBegin(cfg_host->bosHandle, &procIter, &tst2)) {
344             tst = tst2;
345         } else {
346             /* iterate over process names, checking status of each */
347             char procName[BOS_MAX_NAME_LEN];
348             bos_ProcessExecutionState_t procState;
349             char procAuxState[BOS_MAX_NAME_LEN];
350             int procDone = 0;
351
352             while (!procDone) {
353                 if (!bos_ProcessNameGetNext(procIter, procName, &tst2)) {
354                     /* no more processes (or failure) */
355                     if (tst2 != ADMITERATORDONE) {
356                         tst = tst2;
357                     }
358                     procDone = 1;
359
360                 } else
361                     if (!bos_ProcessExecutionStateGet
362                         (cfg_host->bosHandle, procName, &procState,
363                          procAuxState, &tst2)) {
364                     /* process removed (or failure) */
365                     if (tst2 != BZNOENT) {
366                         tst = tst2;
367                         procDone = 1;
368                     }
369
370                 } else {
371                     if (procState != BOS_PROCESS_STOPPED) {
372                         *isBosProcP = 1;
373                         procDone = 1;
374                     }
375                 }
376             }
377
378             if (!bos_ProcessNameGetDone(procIter, &tst2)) {
379                 tst = tst2;
380             }
381         }
382     }
383
384     if (tst != 0) {
385         /* indicate failure */
386         rc = 0;
387     }
388     if (st != NULL) {
389         *st = tst;
390     }
391     return rc;
392 }
393
394
395
396
397 /* ---------------- Exported Database Server functions ------------------ */
398
399
400
401 /*
402  * cfg_AuthServerStart() -- Start authentication server on host and wait
403  *     for server to be ready to accept requests.
404  *
405  *     This function is intended to be used when configuring the first
406  *     machine in a cell; it enables the AFS server principal to be created
407  *     and configured before starting the remaining database servers.
408  */
409 int ADMINAPI
410 cfg_AuthServerStart(void *hostHandle,   /* host config handle */
411                     afs_status_p st)
412 {                               /* completion status */
413     int rc = 1;
414     afs_status_t tst2, tst = 0;
415     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
416
417     /* validate parameters and prepare host handle for bos functions */
418
419     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
420         tst = tst2;
421     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
422         tst = tst2;
423     }
424
425     /* create and start authentication server instance */
426
427     if (tst == 0) {
428         if (!SimpleProcessStart
429             (cfg_host->bosHandle, KASERVER_BOSNAME, KASERVER_EXEPATH, NULL,
430              &tst2)) {
431             tst = tst2;
432         }
433     }
434
435     /* wait for authentication server to achieve quorum */
436
437     if (tst == 0) {
438         time_t timeStart = time(NULL);
439         short kaHasQuorum;
440
441         while (1) {
442             if (!UbikQuorumCheck
443                 (cfg_host, KASERVER_BOSNAME, &kaHasQuorum, &tst2)) {
444                 tst = tst2;
445                 break;
446
447             } else if (kaHasQuorum) {
448                 /* quorum on authentication server */
449                 break;
450
451             } else {
452                 /* quorum not yet achieved on authentication server */
453                 if (difftime(time(NULL), timeStart) > 180) {
454                     tst = ADMCFGQUORUMWAITTIMEOUT;
455                     break;
456                 } else {
457                     cfgutil_Sleep(2);
458                 }
459             }
460         }
461     }
462
463     if (tst != 0) {
464         /* indicate failure */
465         rc = 0;
466     }
467     if (st != NULL) {
468         *st = tst;
469     }
470     return rc;
471 }
472
473
474 /*
475  * cfg_DbServersStart() -- Start the standard (required) database servers,
476  *     and optionally the backup database server, on host.
477  *
478  *     The BOS instance names used are the string constants:
479  *         cfg_kaserverBosName - authentication server
480  *         cfg_ptserverBosName - protection server
481  *         cfg_vlserverBosName - volume location server
482  *         cfg_buserverBosName - backup server
483  */
484 int ADMINAPI
485 cfg_DbServersStart(void *hostHandle,    /* host config handle */
486                    short startBkDb,     /* start backup server */
487                    afs_status_p st)
488 {                               /* completion status */
489     int rc = 1;
490     afs_status_t tst2, tst = 0;
491     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
492
493     /* validate parameters and prepare host handle for bos functions */
494
495     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
496         tst = tst2;
497     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
498         tst = tst2;
499     }
500
501     /* create and start database server instances */
502
503     if (tst == 0) {
504         /* try all regardless of failures; last error code wins */
505         if (!SimpleProcessStart
506             (cfg_host->bosHandle, KASERVER_BOSNAME, KASERVER_EXEPATH, NULL,
507              &tst2)) {
508             tst = tst2;
509         }
510         if (!SimpleProcessStart
511             (cfg_host->bosHandle, PTSERVER_BOSNAME, PTSERVER_EXEPATH, NULL,
512              &tst2)) {
513             tst = tst2;
514         }
515         if (!SimpleProcessStart
516             (cfg_host->bosHandle, VLSERVER_BOSNAME, VLSERVER_EXEPATH, NULL,
517              &tst2)) {
518             tst = tst2;
519         }
520         if (startBkDb
521             && !SimpleProcessStart(cfg_host->bosHandle, BUSERVER_BOSNAME,
522                                    BUSERVER_EXEPATH, NULL, &tst2)) {
523             tst = tst2;
524         }
525     }
526
527     if (tst != 0) {
528         /* indicate failure */
529         rc = 0;
530     }
531     if (st != NULL) {
532         *st = tst;
533     }
534     return rc;
535 }
536
537
538 /*
539  * cfg_DbServersStop() -- Stop, and unconfigure, the database servers on host.
540  */
541 int ADMINAPI
542 cfg_DbServersStop(void *hostHandle,     /* host config handle */
543                   afs_status_p st)
544 {                               /* completion status */
545     int rc = 1;
546     afs_status_t tst2, tst = 0;
547     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
548
549     /* validate parameters and prepare host handle for bos functions */
550
551     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
552         tst = tst2;
553     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
554         tst = tst2;
555     }
556
557     /* stop and delete database server instances */
558
559     if (tst == 0) {
560         /* try all regardless of failures; last error code wins */
561         if (!BosProcessDelete(cfg_host->bosHandle, KASERVER_BOSNAME, &tst2)) {
562             tst = tst2;
563         }
564         if (!BosProcessDelete(cfg_host->bosHandle, PTSERVER_BOSNAME, &tst2)) {
565             tst = tst2;
566         }
567         if (!BosProcessDelete(cfg_host->bosHandle, VLSERVER_BOSNAME, &tst2)) {
568             tst = tst2;
569         }
570         if (!BosProcessDelete(cfg_host->bosHandle, BUSERVER_BOSNAME, &tst2)) {
571             tst = tst2;
572         }
573     }
574
575     if (tst != 0) {
576         /* indicate failure */
577         rc = 0;
578     }
579     if (st != NULL) {
580         *st = tst;
581     }
582     return rc;
583 }
584
585
586 /*
587  * cfg_DbServersQueryStatus() -- Query status of database servers on host.
588  *
589  *     If detailed status information is not required, detailsP can be NULL.
590  *
591  *     If *isStdDbP is FALSE and *isBkDbP is TRUE then the host is in an
592  *     inconsistent state; the remaining database servers should be configured.
593  */
594 int ADMINAPI
595 cfg_DbServersQueryStatus(void *hostHandle,      /* host config handle */
596                          short *isStdDbP,       /* std DB servers configured */
597                          short *isBkDbP,        /* backup DB server configured */
598                          cfg_dbServersStatus_t * detailsP,      /* config details */
599                          afs_status_p st)
600 {                               /* completion status */
601     int rc = 1;
602     afs_status_t tst2, tst = 0;
603     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
604     short inCellServDb, isKaserver, isPtserver, isVlserver, isBuserver;
605
606     inCellServDb = isKaserver = isPtserver = isVlserver = isBuserver = 0;
607
608     /* validate parameters and prepare host handle for bos functions */
609
610     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
611         tst = tst2;
612     } else if (isStdDbP == NULL || isBkDbP == NULL) {
613         tst = ADMCFGDBSERVERCONFIGFLAGPNULL;
614     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
615         tst = tst2;
616     }
617
618     /* query host's server CellServDb to see if it lists itself */
619
620     if (tst == 0) {
621         char hostNameAlias[MAXHOSTCHARS];
622
623         if (!cfgutil_HostNameGetCellServDbAlias
624             (cfg_host->hostName, cfg_host->hostName, hostNameAlias, &tst2)) {
625             tst = tst2;
626         } else if (*hostNameAlias != '\0') {
627             /* host in its own CellServDb */
628             inCellServDb = 1;
629         }
630     }
631
632     /* query bosserver to determine what database servers are configured */
633
634     if (tst == 0) {
635         bos_ProcessType_t procType;
636         bos_ProcessInfo_t procInfo;
637
638         if (bos_ProcessInfoGet
639             (cfg_host->bosHandle, KASERVER_BOSNAME, &procType, &procInfo,
640              &tst2)) {
641             isKaserver = 1;
642         } else if (tst2 != BZNOENT) {
643             tst = tst2;
644         }
645
646         if (tst == 0) {
647             if (bos_ProcessInfoGet
648                 (cfg_host->bosHandle, PTSERVER_BOSNAME, &procType, &procInfo,
649                  &tst2)) {
650                 isPtserver = 1;
651             } else if (tst2 != BZNOENT) {
652                 tst = tst2;
653             }
654         }
655
656         if (tst == 0) {
657             if (bos_ProcessInfoGet
658                 (cfg_host->bosHandle, VLSERVER_BOSNAME, &procType, &procInfo,
659                  &tst2)) {
660                 isVlserver = 1;
661             } else if (tst2 != BZNOENT) {
662                 tst = tst2;
663             }
664         }
665
666         if (tst == 0) {
667             if (bos_ProcessInfoGet
668                 (cfg_host->bosHandle, BUSERVER_BOSNAME, &procType, &procInfo,
669                  &tst2)) {
670                 isBuserver = 1;
671             } else if (tst2 != BZNOENT) {
672                 tst = tst2;
673             }
674         }
675     }
676
677     if (tst == 0) {
678         /* success; return results */
679         *isStdDbP = (inCellServDb && isKaserver && isPtserver && isVlserver);
680         *isBkDbP = (inCellServDb && isBuserver);
681
682         if (detailsP) {
683             detailsP->inCellServDb = inCellServDb;
684             detailsP->isKaserver = isKaserver;
685             detailsP->isPtserver = isPtserver;
686             detailsP->isVlserver = isVlserver;
687             detailsP->isBuserver = isBuserver;
688         }
689     } else {
690         /* indicate failure */
691         rc = 0;
692     }
693     if (st != NULL) {
694         *st = tst;
695     }
696     return rc;
697 }
698
699
700 /*
701  * cfg_DbServersRestartAll() -- Restart all database servers in host's cell.
702  */
703 int ADMINAPI
704 cfg_DbServersRestartAll(void *hostHandle,       /* host config handle */
705                         afs_status_p st)
706 {                               /* completion status */
707     int rc = 1;
708     afs_status_t tst2, tst = 0;
709     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
710
711     /* validate parameters and prepare host handle for bos functions */
712
713     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
714         tst = tst2;
715     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
716         tst = tst2;
717     }
718
719     /* restart all database servers in host's cell */
720
721     if (tst == 0) {
722         void *dbIter;
723
724         if (!bos_HostGetBegin(cfg_host->bosHandle, &dbIter, &tst2)) {
725             tst = tst2;
726         } else {
727             /* iterate over server CellServDb, restarting db servers */
728             char dbhostName[BOS_MAX_NAME_LEN];
729             void *dbhostHandle;
730             int dbhostDone = 0;
731
732             while (!dbhostDone) {
733                 if (!bos_HostGetNext(dbIter, dbhostName, &tst2)) {
734                     /* no more entries (or failure) */
735                     if (tst2 != ADMITERATORDONE) {
736                         tst = tst2;
737                     }
738                     dbhostDone = 1;
739
740                 } else
741                     if (!bos_ServerOpen
742                         (cfg_host->cellHandle, dbhostName, &dbhostHandle,
743                          &tst2)) {
744                     /* failed to get bos handle; note error but keep going */
745                     tst = tst2;
746
747                 } else {
748                     /* restart db servers; note errors, but keep going */
749                     if (!bos_ProcessRestart
750                         (dbhostHandle, KASERVER_BOSNAME, &tst2)) {
751                         tst = tst2;
752                     }
753                     if (!bos_ProcessRestart
754                         (dbhostHandle, PTSERVER_BOSNAME, &tst2)) {
755                         tst = tst2;
756                     }
757                     if (!bos_ProcessRestart
758                         (dbhostHandle, VLSERVER_BOSNAME, &tst2)) {
759                         tst = tst2;
760                     }
761                     if (!bos_ProcessRestart
762                         (dbhostHandle, BUSERVER_BOSNAME, &tst2)) {
763                         /* may not be running a backup server */
764                         if (tst2 != BZNOENT) {
765                             tst = tst2;
766                         }
767                     }
768
769                     if (!bos_ServerClose(dbhostHandle, &tst2)) {
770                         tst = tst2;
771                     }
772                 }
773             }
774
775             if (!bos_HostGetDone(dbIter, &tst2)) {
776                 tst = tst2;
777             }
778         }
779     }
780
781     if (tst != 0) {
782         /* indicate failure */
783         rc = 0;
784
785         /* should really utilize a callback (or some other mechanism) to
786          * indicate which restarts failed and why.
787          */
788     }
789     if (st != NULL) {
790         *st = tst;
791     }
792     return rc;
793 }
794
795
796 /*
797  * cfg_DbServersWaitForQuorum() -- Wait for database servers in host's cell
798  *     to achieve quorum.
799  *
800  *     Timeout is the maximum time, in seconds, to wait for quorum.
801  *
802  *     NOTE: Function does not check for backup server quorum since
803  *           configuration does not require modifying the backup database.
804  */
805 int ADMINAPI
806 cfg_DbServersWaitForQuorum(void *hostHandle,    /* host config handle */
807                            unsigned int timeout,        /* timeout in sec. */
808                            afs_status_p st)
809 {                               /* completion status */
810     int rc = 1;
811     afs_status_t tst2, tst = 0;
812     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
813
814     /* validate parameters and prepare host handle for bos functions */
815
816     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
817         tst = tst2;
818     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
819         tst = tst2;
820     }
821
822     /* wait for the database servers in host's cell to achieve quorum */
823
824     if (tst == 0) {
825         time_t timeStart = time(NULL);
826         short kaHasQuorum, ptHasQuorum, vlHasQuorum;
827
828         kaHasQuorum = ptHasQuorum = vlHasQuorum = 0;
829
830         while (1) {
831             if (!kaHasQuorum) {
832                 if (!UbikQuorumCheck
833                     (cfg_host, KASERVER_BOSNAME, &kaHasQuorum, &tst2)) {
834                     tst = tst2;
835                     break;
836                 }
837             }
838
839             if (!ptHasQuorum) {
840                 if (!UbikQuorumCheck
841                     (cfg_host, PTSERVER_BOSNAME, &ptHasQuorum, &tst2)) {
842                     tst = tst2;
843                     break;
844                 }
845             }
846
847             if (!vlHasQuorum) {
848                 if (!UbikQuorumCheck
849                     (cfg_host, VLSERVER_BOSNAME, &vlHasQuorum, &tst2)) {
850                     tst = tst2;
851                     break;
852                 }
853             }
854
855             if (kaHasQuorum && ptHasQuorum && vlHasQuorum) {
856                 /* quorum on all dbservers of interest */
857                 break;
858             } else {
859                 /* quorum not yet achieved for one or more dbservers */
860                 if ((timeout == 0)
861                     || (difftime(time(NULL), timeStart) > timeout)) {
862                     tst = ADMCFGQUORUMWAITTIMEOUT;
863                     break;
864                 } else {
865                     cfgutil_Sleep(10);
866                 }
867             }
868         }
869     }
870
871     if (tst != 0) {
872         /* indicate failure */
873         rc = 0;
874     }
875     if (st != NULL) {
876         *st = tst;
877     }
878     return rc;
879 }
880
881
882
883 /*
884  * cfg_DbServersStopAllBackup() -- Stop, and unconfigure, all backup servers
885  *     in host's cell.
886  */
887 int ADMINAPI
888 cfg_DbServersStopAllBackup(void *hostHandle,    /* host config handle */
889                            afs_status_p st)
890 {                               /* completion status */
891     int rc = 1;
892     afs_status_t tst2, tst = 0;
893     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
894
895     /* validate parameters and prepare host handle for bos functions */
896
897     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
898         tst = tst2;
899     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
900         tst = tst2;
901     }
902
903     /* stop and delete all backup servers in host's cell */
904
905     if (tst == 0) {
906         void *dbIter;
907
908         if (!bos_HostGetBegin(cfg_host->bosHandle, &dbIter, &tst2)) {
909             tst = tst2;
910         } else {
911             /* iterate over server CellServDb, unconfiguring backup servers */
912             char dbhostName[BOS_MAX_NAME_LEN];
913             void *dbhostHandle;
914             int dbhostDone = 0;
915
916             while (!dbhostDone) {
917                 if (!bos_HostGetNext(dbIter, dbhostName, &tst2)) {
918                     /* no more entries (or failure) */
919                     if (tst2 != ADMITERATORDONE) {
920                         tst = tst2;
921                     }
922                     dbhostDone = 1;
923
924                 } else
925                     if (!bos_ServerOpen
926                         (cfg_host->cellHandle, dbhostName, &dbhostHandle,
927                          &tst2)) {
928                     /* failed to get bos handle; note error but keep going */
929                     tst = tst2;
930
931                 } else {
932                     /* unconfig backup server; note errors, but keep going */
933                     if (!BosProcessDelete
934                         (dbhostHandle, BUSERVER_BOSNAME, &tst2)) {
935                         tst = tst2;
936                     }
937
938                     if (!bos_ServerClose(dbhostHandle, &tst2)) {
939                         tst = tst2;
940                     }
941                 }
942             }
943
944             if (!bos_HostGetDone(dbIter, &tst2)) {
945                 tst = tst2;
946             }
947         }
948     }
949
950     if (tst != 0) {
951         /* indicate failure */
952         rc = 0;
953
954         /* should really utilize a callback (or some other mechanism) to
955          * indicate which stops failed and why.
956          */
957     }
958     if (st != NULL) {
959         *st = tst;
960     }
961     return rc;
962 }
963
964
965
966
967
968 /* ---------------- Exported File Server functions ------------------ */
969
970
971 /*
972  * cfg_FileServerStart() -- Start the file server on host.
973  *
974  *     The BOS instance name used is the string constant cfg_fileserverBosName.
975  */
976 int ADMINAPI
977 cfg_FileServerStart(void *hostHandle,   /* host config handle */
978                     afs_status_p st)
979 {                               /* completion status */
980     int rc = 1;
981     afs_status_t tst2, tst = 0;
982     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
983
984     /* validate parameters and prepare host handle for bos functions */
985
986     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
987         tst = tst2;
988     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
989         tst = tst2;
990     }
991
992     /* create and start file server instance */
993
994     if (tst == 0) {
995         if (!FsProcessStart
996             (cfg_host->bosHandle, FILESERVER_BOSNAME, FILESERVER_EXEPATH,
997              VOLSERVER_EXEPATH, SALVAGER_EXEPATH, &tst2)) {
998             tst = tst2;
999         } else {
1000             /* TO BE DONE: need a reliable "is started and ready" check */
1001             cfgutil_Sleep(5);
1002         }
1003     }
1004
1005     if (tst != 0) {
1006         /* indicate failure */
1007         rc = 0;
1008     }
1009     if (st != NULL) {
1010         *st = tst;
1011     }
1012     return rc;
1013 }
1014
1015
1016 /*
1017  * cfg_FileServerStop() -- Stop, and unconfigure, the file server on host.
1018  */
1019 int ADMINAPI
1020 cfg_FileServerStop(void *hostHandle,    /* host config handle */
1021                    afs_status_p st)
1022 {                               /* completion status */
1023     int rc = 1;
1024     afs_status_t tst2, tst = 0;
1025     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1026
1027     /* validate parameters and prepare host handle for bos functions */
1028
1029     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1030         tst = tst2;
1031     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1032         tst = tst2;
1033     }
1034
1035     /* stop and delete file server instance */
1036
1037     if (tst == 0) {
1038         if (!BosProcessDelete(cfg_host->bosHandle, FILESERVER_BOSNAME, &tst2)) {
1039             tst = tst2;
1040         } else {
1041             /* file server instance deleted; remove its addresses from VLDB */
1042             int addrCount, i;
1043             afs_int32 *addrList = NULL;
1044
1045             /* note: ignore any errors since address removal is optional;
1046              * e.g., a common source of errors will be attempting to remove
1047              * an address while volumes tied to that address are still listed
1048              * in the VLDB (in which case the address is not removed).
1049              */
1050             if (cfgutil_HostAddressFetchAll
1051                 (cfg_host->hostName, &addrCount, &addrList, &tst2)) {
1052                 for (i = 0; i < addrCount; i++) {
1053                     (void)vos_FileServerAddressRemove(cfg_host->cellHandle,
1054                                                       NULL, addrList[i],
1055                                                       &tst2);
1056                 }
1057                         if (addrList) {
1058                                 free(addrList);
1059                                 addrList = NULL;
1060                         }
1061             }
1062         }
1063     }
1064
1065     if (tst != 0) {
1066         /* indicate failure */
1067         rc = 0;
1068     }
1069     if (st != NULL) {
1070         *st = tst;
1071     }
1072     return rc;
1073 }
1074
1075
1076 /*
1077  * cfg_FileServerQueryStatus() -- Query status of file server on host.
1078  */
1079 int ADMINAPI
1080 cfg_FileServerQueryStatus(void *hostHandle,     /* host config handle */
1081                           short *isFsP, /* file server configured */
1082                           afs_status_p st)
1083 {                               /* completion status */
1084     int rc = 1;
1085     afs_status_t tst2, tst = 0;
1086     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1087
1088     /* validate parameters and prepare host handle for bos functions */
1089
1090     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1091         tst = tst2;
1092     } else if (isFsP == NULL) {
1093         tst = ADMCFGFILESERVERCONFIGFLAGPNULL;
1094     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1095         tst = tst2;
1096     }
1097
1098     /* query bosserver to determine if fileserver is configured */
1099
1100     if (tst == 0) {
1101         bos_ProcessType_t procType;
1102         bos_ProcessInfo_t procInfo;
1103
1104         *isFsP = 0;
1105
1106         if (bos_ProcessInfoGet
1107             (cfg_host->bosHandle, FILESERVER_BOSNAME, &procType, &procInfo,
1108              &tst2)) {
1109             /* instance exists; check type for good measure */
1110             if (procType == BOS_PROCESS_FS) {
1111                 *isFsP = 1;
1112             }
1113         } else if (tst2 != BZNOENT) {
1114             tst = tst2;
1115         }
1116     }
1117
1118     if (tst != 0) {
1119         /* indicate failure */
1120         rc = 0;
1121     }
1122     if (st != NULL) {
1123         *st = tst;
1124     }
1125     return rc;
1126 }
1127
1128
1129
1130
1131 /* ---------------- Exported Update Server functions ------------------ */
1132
1133
1134
1135 /*
1136  * cfg_UpdateServerStart() -- Start the Update server on host.
1137  *
1138  *     Argument strings exportClear and exportCrypt each specify a set of
1139  *     space-separated directories to export or are NULL.
1140  *
1141  *     The BOS instance name used is the string constant cfg_upserverBosName.
1142  */
1143 int ADMINAPI
1144 cfg_UpdateServerStart(void *hostHandle, /* host config handle */
1145                       const char *exportClear,  /* dirs to export in clear */
1146                       const char *exportCrypt,  /* dirs to export encrypted */
1147                       afs_status_p st)
1148 {                               /* completion status */
1149     int rc = 1;
1150     afs_status_t tst2, tst = 0;
1151     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1152
1153     /* validate parameters and prepare host handle for bos functions */
1154
1155     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1156         tst = tst2;
1157     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1158         tst = tst2;
1159     }
1160
1161     /* stop and delete existing update server instance, if any.
1162      * we do this because the set of exported directores might be changing.
1163      */
1164
1165     if (tst == 0) {
1166         if (!BosProcessDelete(cfg_host->bosHandle, UPSERVER_BOSNAME, &tst2)) {
1167             tst = tst2;
1168         }
1169     }
1170
1171     /* create and start update server instance */
1172
1173     if (tst == 0) {
1174         char argsBuf[AFSDIR_PATH_MAX], *args;
1175         size_t argsLen = 0;
1176
1177         if (exportClear != NULL && *exportClear != '\0') {
1178             argsLen += strlen("-clear ") + strlen(exportClear) + 1;
1179         }
1180         if (exportCrypt != NULL && *exportCrypt != '\0') {
1181             argsLen += strlen("-crypt ") + strlen(exportCrypt) + 1;
1182         }
1183
1184         if (argsLen == 0) {
1185             args = NULL;
1186         } else {
1187             if (argsLen <= AFSDIR_PATH_MAX) {
1188                 args = argsBuf;
1189             } else {
1190                 args = (char *)malloc(argsLen);
1191             }
1192
1193             if (args == NULL) {
1194                 tst = ADMNOMEM;
1195             } else {
1196                 if (exportClear == NULL) {
1197                     sprintf(args, "-crypt %s", exportCrypt);
1198                 } else if (exportCrypt == NULL) {
1199                     sprintf(args, "-clear %s", exportClear);
1200                 } else {
1201                     sprintf(args, "-clear %s -crypt %s", exportClear,
1202                             exportCrypt);
1203                 }
1204             }
1205         }
1206
1207         if (tst == 0) {
1208             if (!SimpleProcessStart
1209                 (cfg_host->bosHandle, UPSERVER_BOSNAME, UPSERVER_EXEPATH,
1210                  args, &tst2)) {
1211                 tst = tst2;
1212             }
1213
1214             if (args != NULL && args != argsBuf) {
1215                         free(args);
1216             }
1217         }
1218     }
1219
1220     if (tst != 0) {
1221         /* indicate failure */
1222         rc = 0;
1223     }
1224     if (st != NULL) {
1225         *st = tst;
1226     }
1227     return rc;
1228 }
1229
1230
1231 /*
1232  * cfg_UpdateServerStop() -- Stop, and unconfigure, the Update server on host.
1233  */
1234 int ADMINAPI
1235 cfg_UpdateServerStop(void *hostHandle,  /* host config handle */
1236                      afs_status_p st)
1237 {                               /* completion status */
1238     int rc = 1;
1239     afs_status_t tst2, tst = 0;
1240     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1241
1242     /* validate parameters and prepare host handle for bos functions */
1243
1244     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1245         tst = tst2;
1246     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1247         tst = tst2;
1248     }
1249
1250     /* stop and delete upserver instance */
1251
1252     if (tst == 0) {
1253         if (!BosProcessDelete(cfg_host->bosHandle, UPSERVER_BOSNAME, &tst2)) {
1254             tst = tst2;
1255         }
1256     }
1257
1258     if (tst != 0) {
1259         /* indicate failure */
1260         rc = 0;
1261     }
1262     if (st != NULL) {
1263         *st = tst;
1264     }
1265     return rc;
1266 }
1267
1268
1269 /*
1270  * cfg_UpdateServerQueryStatus() -- Query status of Update server on host.
1271  */
1272 int ADMINAPI
1273 cfg_UpdateServerQueryStatus(void *hostHandle,   /* host config handle */
1274                             short *isUpserverP, /* update server configured */
1275                             short *isSysCtrlP,  /* system control configured */
1276                             short *isBinDistP,  /* binary dist configured */
1277                             afs_status_p st)
1278 {                               /* completion status */
1279     int rc = 1;
1280     afs_status_t tst2, tst = 0;
1281     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1282
1283     /* validate parameters and prepare host handle for bos functions */
1284
1285     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1286         tst = tst2;
1287     } else if (isUpserverP == NULL || isSysCtrlP == NULL
1288                || isBinDistP == NULL) {
1289         tst = ADMCFGUPSERVERCONFIGFLAGPNULL;
1290     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1291         tst = tst2;
1292     }
1293
1294     /* query bosserver to determine if, and how, upserver is configured */
1295
1296     if (tst == 0) {
1297         void *cmdIter;
1298
1299         *isUpserverP = *isSysCtrlP = *isBinDistP = 0;
1300
1301         if (!bos_ProcessParameterGetBegin
1302             (cfg_host->bosHandle, UPSERVER_BOSNAME, &cmdIter, &tst2)) {
1303             tst = tst2;
1304         } else {
1305             char cmdString[BOS_MAX_NAME_LEN];
1306
1307             if (!bos_ProcessParameterGetNext(cmdIter, cmdString, &tst2)) {
1308                 /* no upserver instance (or error) */
1309                 if (tst2 != BZNOENT) {
1310                     tst = tst2;
1311                 }
1312             } else {
1313                 /* parse upserver command line to determine how configured */
1314                 short hasSysPath, hasBinPath;
1315
1316                 UpdateCommandParse(cmdString, &hasSysPath, &hasBinPath);
1317
1318                 *isUpserverP = 1;
1319
1320                 if (hasSysPath) {
1321                     *isSysCtrlP = 1;
1322                 }
1323                 if (hasBinPath) {
1324                     *isBinDistP = 1;
1325                 }
1326             }
1327
1328             if (!bos_ProcessParameterGetDone(cmdIter, &tst2)) {
1329                 tst = tst2;
1330             }
1331         }
1332     }
1333
1334     if (tst != 0) {
1335         /* indicate failure */
1336         rc = 0;
1337     }
1338     if (st != NULL) {
1339         *st = tst;
1340     }
1341     return rc;
1342 }
1343
1344
1345 /*
1346  * cfg_SysBinServerStart() -- Start Update server in System Control and/or
1347  *     Binary Distribution machine configuration on host.
1348  *
1349  *     This function is a convenience wrapper for cfg_UpdateServerStart().
1350  */
1351 int ADMINAPI
1352 cfg_SysBinServerStart(void *hostHandle, /* host config handle */
1353                       short makeSysCtrl,        /* config as sys control mach */
1354                       short makeBinDist,        /* config as binary dist mach */
1355                       afs_status_p st)
1356 {                               /* completion status */
1357     char *cryptSysDir = NULL;
1358     char *clearBinDir = NULL;
1359
1360     if (makeSysCtrl) {
1361         cryptSysDir = AFSDIR_CANONICAL_SERVER_ETC_DIRPATH;
1362     }
1363
1364     if (makeBinDist) {
1365         clearBinDir = AFSDIR_CANONICAL_SERVER_BIN_DIRPATH;
1366     }
1367
1368     return cfg_UpdateServerStart(hostHandle, clearBinDir, cryptSysDir, st);
1369 }
1370
1371
1372
1373 /* ---------------- Exported Update Client functions ------------------ */
1374
1375
1376
1377 /*
1378  * cfg_UpdateClientStart() -- Start an Update client on host.
1379  *
1380  *     Argument string import specifies a set of space-separated directories
1381  *     to import.  Argument frequency specifies the import interval in
1382  *     seconds; if the value is zero (0) then the default frequency is used.
1383  *
1384  *     The BOS instance name used is the concatenation of the string constant
1385  *     cfg_upclientBosNamePrefix and the argument string bosSuffix.
1386  */
1387 int ADMINAPI
1388 cfg_UpdateClientStart(void *hostHandle, /* host config handle */
1389                       const char *bosSuffix,    /* BOS instance suffix */
1390                       const char *upserver,     /* upserver to import from */
1391                       short crypt,      /* import encrypted */
1392                       const char *import,       /* dirs to import */
1393                       unsigned int frequency,   /* import interval in sec. */
1394                       afs_status_p st)
1395 {                               /* completion status */
1396     int rc = 1;
1397     afs_status_t tst2, tst = 0;
1398     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1399     char upclientInstance[BOS_MAX_NAME_LEN];
1400
1401     /* validate parameters and prepare host handle for bos functions */
1402
1403     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1404         tst = tst2;
1405     } else if (bosSuffix == NULL) {
1406         tst = ADMCFGUPCLIENTSUFFIXNULL;
1407     } else if ((strlen(UPCLIENT_BOSNAME) + strlen(bosSuffix) + 1) >
1408                BOS_MAX_NAME_LEN) {
1409         tst = ADMCFGUPCLIENTSUFFIXTOOLONG;
1410     } else if (upserver == NULL || *upserver == '\0') {
1411         tst = ADMCFGUPCLIENTTARGETSERVERNULL;
1412     } else if (import == NULL || *import == '\0') {
1413         tst = ADMCFGUPCLIENTIMPORTDIRNULL;
1414     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1415         tst = tst2;
1416     }
1417
1418     /* stop and delete existing update client instance, if any.
1419      * we do this because the set of imported directores might be changing.
1420      */
1421
1422     if (tst == 0) {
1423         sprintf(upclientInstance, "%s%s", UPCLIENT_BOSNAME, bosSuffix);
1424
1425         if (!BosProcessDelete(cfg_host->bosHandle, upclientInstance, &tst2)) {
1426             tst = tst2;
1427         }
1428     }
1429
1430     /* create and start update client instance */
1431
1432     if (tst == 0) {
1433         char argsBuf[AFSDIR_PATH_MAX], *args;
1434         size_t argsLen = 0;
1435
1436         argsLen += strlen(upserver) + 1;
1437
1438         if (crypt) {
1439             argsLen += strlen("-crypt ");
1440         } else {
1441             argsLen += strlen("-clear ");
1442         }
1443
1444         if (frequency != 0) {
1445             argsLen += strlen("-t ") + 10 /* max uint */  + 1;
1446         }
1447
1448         argsLen += strlen(import) + 1;
1449
1450         if (argsLen <= AFSDIR_PATH_MAX) {
1451             args = argsBuf;
1452         } else {
1453             args = (char *)malloc(argsLen);
1454         }
1455
1456         if (args == NULL) {
1457             tst = ADMNOMEM;
1458         } else {
1459             /* set up argument buffer */
1460             if (crypt) {
1461                 sprintf(args, "%s -crypt ", upserver);
1462             } else {
1463                 sprintf(args, "%s -clear ", upserver);
1464             }
1465             if (frequency != 0) {
1466                 char *strp = args + strlen(args);
1467                 sprintf(strp, "-t %u ", frequency);
1468             }
1469             strcat(args, import);
1470
1471             /* create and start instance */
1472             if (!SimpleProcessStart
1473                 (cfg_host->bosHandle, upclientInstance, UPCLIENT_EXEPATH,
1474                  args, &tst2)) {
1475                 tst = tst2;
1476             }
1477
1478             if (args != argsBuf) {
1479                         free(args);
1480             }
1481         }
1482     }
1483
1484     if (tst != 0) {
1485         /* indicate failure */
1486         rc = 0;
1487     }
1488     if (st != NULL) {
1489         *st = tst;
1490     }
1491     return rc;
1492 }
1493
1494
1495 /*
1496  * cfg_UpdateClientStop() -- Stop, and unconfigure, an Update client on host.
1497  */
1498 int ADMINAPI
1499 cfg_UpdateClientStop(void *hostHandle,  /* host config handle */
1500                      const char *bosSuffix,     /* BOS instance suffix */
1501                      afs_status_p st)
1502 {                               /* completion status */
1503     int rc = 1;
1504     afs_status_t tst2, tst = 0;
1505     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1506     char upclientInstance[BOS_MAX_NAME_LEN];
1507
1508     /* validate parameters and prepare host handle for bos functions */
1509
1510     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1511         tst = tst2;
1512     } else if (bosSuffix == NULL) {
1513         tst = ADMCFGUPCLIENTSUFFIXNULL;
1514     } else if ((strlen(UPCLIENT_BOSNAME) + strlen(bosSuffix) + 1) >
1515                BOS_MAX_NAME_LEN) {
1516         tst = ADMCFGUPCLIENTSUFFIXTOOLONG;
1517     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1518         tst = tst2;
1519     }
1520
1521     /* stop and delete specified update client instance */
1522
1523     if (tst == 0) {
1524         sprintf(upclientInstance, "%s%s", UPCLIENT_BOSNAME, bosSuffix);
1525
1526         if (!BosProcessDelete(cfg_host->bosHandle, upclientInstance, &tst2)) {
1527             tst = tst2;
1528         }
1529     }
1530
1531     if (tst != 0) {
1532         /* indicate failure */
1533         rc = 0;
1534     }
1535     if (st != NULL) {
1536         *st = tst;
1537     }
1538     return rc;
1539 }
1540
1541
1542 /*
1543  * cfg_UpdateClientStopAll() -- Stop, and unconfigure, all Update clients
1544  *     on host.
1545  */
1546 int ADMINAPI
1547 cfg_UpdateClientStopAll(void *hostHandle,       /* host config handle */
1548                         afs_status_p st)
1549 {                               /* completion status */
1550     int rc = 1;
1551     afs_status_t tst2, tst = 0;
1552     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1553
1554     /* validate parameters and prepare host handle for bos functions */
1555
1556     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1557         tst = tst2;
1558     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1559         tst = tst2;
1560     }
1561
1562     /* find, stop, and delete all update client instances */
1563
1564     if (tst == 0) {
1565         void *procIter;
1566
1567         if (!bos_ProcessNameGetBegin(cfg_host->bosHandle, &procIter, &tst2)) {
1568             tst = tst2;
1569         } else {
1570             /* iterate over process names, looking for update clients */
1571             char procName[BOS_MAX_NAME_LEN];
1572             int procDone = 0;
1573
1574             while (!procDone) {
1575                 if (!bos_ProcessNameGetNext(procIter, procName, &tst2)) {
1576                     /* no more processes (or failure) */
1577                     if (tst2 != ADMITERATORDONE) {
1578                         tst = tst2;
1579                     }
1580                     procDone = 1;
1581
1582                 } else
1583                     if (!strncmp
1584                         (UPCLIENT_BOSNAME, procName,
1585                          (sizeof(UPCLIENT_BOSNAME) - 1))) {
1586                     /* upclient instance prefix; assume is upclient */
1587                     if (!BosProcessDelete
1588                         (cfg_host->bosHandle, procName, &tst2)) {
1589                         tst = tst2;
1590                         procDone = 1;
1591                     }
1592                 }
1593             }
1594
1595             if (!bos_ProcessNameGetDone(procIter, &tst2)) {
1596                 tst = tst2;
1597             }
1598         }
1599     }
1600
1601     if (tst != 0) {
1602         /* indicate failure */
1603         rc = 0;
1604     }
1605     if (st != NULL) {
1606         *st = tst;
1607     }
1608     return rc;
1609 }
1610
1611
1612 /*
1613  * cfg_UpdateClientQueryStatus() -- Query status of Update clients on host.
1614  */
1615 int ADMINAPI
1616 cfg_UpdateClientQueryStatus(void *hostHandle,   /* host config handle */
1617                             short *isUpclientP, /* an upclient is configured */
1618                             short *isSysP,      /* system control client */
1619                             short *isBinP,      /* binary dist. client */
1620                             afs_status_p st)
1621 {                               /* completion status */
1622     int rc = 1;
1623     afs_status_t tst2, tst = 0;
1624     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1625
1626     /* validate parameters and prepare host handle for bos functions */
1627
1628     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1629         tst = tst2;
1630     } else if (isUpclientP == NULL || isSysP == NULL || isBinP == NULL) {
1631         tst = ADMCFGUPCLIENTCONFIGFLAGPNULL;
1632     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1633         tst = tst2;
1634     }
1635
1636     /* determine if, and how, any upclients are configured */
1637
1638     if (tst == 0) {
1639         void *procIter;
1640
1641         *isUpclientP = *isSysP = *isBinP = 0;
1642
1643         if (!bos_ProcessNameGetBegin(cfg_host->bosHandle, &procIter, &tst2)) {
1644             tst = tst2;
1645         } else {
1646             /* iterate over process names, looking for update clients */
1647             char procName[BOS_MAX_NAME_LEN];
1648             int procDone = 0;
1649
1650             while (!procDone) {
1651                 if (!bos_ProcessNameGetNext(procIter, procName, &tst2)) {
1652                     /* no more processes (or failure) */
1653                     if (tst2 != ADMITERATORDONE) {
1654                         tst = tst2;
1655                     }
1656                     procDone = 1;
1657
1658                 } else
1659                     if (!strncmp
1660                         (UPCLIENT_BOSNAME, procName,
1661                          (sizeof(UPCLIENT_BOSNAME) - 1))) {
1662                     /* upclient instance prefix; assume is upclient */
1663                     void *cmdIter;
1664
1665                     *isUpclientP = 1;
1666
1667                     if (!bos_ProcessParameterGetBegin
1668                         (cfg_host->bosHandle, procName, &cmdIter, &tst2)) {
1669                         tst = tst2;
1670                     } else {
1671                         char cmdString[BOS_MAX_NAME_LEN];
1672
1673                         if (!bos_ProcessParameterGetNext
1674                             (cmdIter, cmdString, &tst2)) {
1675                             /* instance deleted out from under us (or error) */
1676                             if (tst2 != BZNOENT) {
1677                                 tst = tst2;
1678                             }
1679                         } else {
1680                             /* parse command line to determine how config */
1681                             short hasSysPath, hasBinPath;
1682
1683                             UpdateCommandParse(cmdString, &hasSysPath,
1684                                                &hasBinPath);
1685
1686                             if (hasSysPath) {
1687                                 *isSysP = 1;
1688                             }
1689                             if (hasBinPath) {
1690                                 *isBinP = 1;
1691                             }
1692                         }
1693
1694                         if (!bos_ProcessParameterGetDone(cmdIter, &tst2)) {
1695                             tst = tst2;
1696                         }
1697                     }
1698
1699                     if (tst != 0) {
1700                         procDone = 1;
1701                     }
1702                 }
1703             }                   /* while() */
1704
1705             if (!bos_ProcessNameGetDone(procIter, &tst2)) {
1706                 tst = tst2;
1707             }
1708         }
1709     }
1710
1711     if (tst != 0) {
1712         /* indicate failure */
1713         rc = 0;
1714     }
1715     if (st != NULL) {
1716         *st = tst;
1717     }
1718     return rc;
1719 }
1720
1721
1722 /*
1723  * cfg_SysControlClientStart() -- Start an Update client in System Control
1724  *     client configuration on host.
1725  *
1726  *     This function is a convenience wrapper for cfg_UpdateClientStart().
1727  *     The BOS instance suffix used is the constant cfg_upclientSysBosSuffix.
1728  */
1729 int ADMINAPI
1730 cfg_SysControlClientStart(void *hostHandle,     /* host config handle */
1731                           const char *upserver, /* upserver to import from */
1732                           afs_status_p st)
1733 {                               /* completion status */
1734     return cfg_UpdateClientStart(hostHandle, cfg_upclientSysBosSuffix,
1735                                  upserver, 1 /* crypt */ ,
1736                                  AFSDIR_CANONICAL_SERVER_ETC_DIRPATH,
1737                                  0 /* default frequency */ ,
1738                                  st);
1739 }
1740
1741
1742 /*
1743  * cfg_BinDistClientStart() -- Start an Update client in Binary Distribution
1744  *     client configuration on host.
1745  *
1746  *     This function is a convenience wrapper for cfg_UpdateClientStart().
1747  *     The BOS instance suffix used is the constant cfg_upclientBinBosSuffix.
1748  */
1749 int ADMINAPI
1750 cfg_BinDistClientStart(void *hostHandle,        /* host config handle */
1751                        const char *upserver,    /* upserver to import from */
1752                        afs_status_p st)
1753 {                               /* completion status */
1754     return cfg_UpdateClientStart(hostHandle, cfg_upclientBinBosSuffix,
1755                                  upserver, 0 /* crypt */ ,
1756                                  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH,
1757                                  0 /* default frequency */ ,
1758                                  st);
1759 }
1760
1761
1762
1763 /* ---------------- Local functions ------------------ */
1764
1765 /*
1766  * SimpleProcessStart() -- create and start a simple bosserver instance.
1767  *
1768  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1769  */
1770 static int
1771 SimpleProcessStart(void *bosHandle, const char *instance,
1772                    const char *executable, const char *args, afs_status_p st)
1773 {
1774     int rc = 1;
1775     afs_status_t tst2, tst = 0;
1776     char cmdBuf[AFSDIR_PATH_MAX], *cmd;
1777     size_t cmdLen;
1778
1779     cmdLen = strlen(executable) + 1 + (args == NULL ? 0 : (strlen(args) + 1));
1780
1781     if (cmdLen <= AFSDIR_PATH_MAX) {
1782         cmd = cmdBuf;
1783     } else {
1784         cmd = (char *)malloc(cmdLen);
1785     }
1786
1787     if (cmd == NULL) {
1788         tst = ADMNOMEM;
1789     } else {
1790         if (args == NULL) {
1791             strcpy(cmd, executable);
1792         } else {
1793             sprintf(cmd, "%s %s", executable, args);
1794         }
1795
1796         if (!bos_ProcessCreate
1797             (bosHandle, (char *)instance, BOS_PROCESS_SIMPLE, cmd, NULL, NULL, &tst2)
1798             && tst2 != BZEXISTS) {
1799             /* failed to create instance (and not because existed) */
1800             tst = tst2;
1801         } else
1802             if (!bos_ProcessExecutionStateSet
1803                 (bosHandle, (char *)instance, BOS_PROCESS_RUNNING, &tst2)) {
1804             /* failed to set instance state to running */
1805             tst = tst2;
1806         }
1807
1808         if (cmd != cmdBuf) {
1809             free(cmd);
1810         }
1811     }
1812
1813     if (tst != 0) {
1814         /* indicate failure */
1815         rc = 0;
1816     }
1817     if (st != NULL) {
1818         *st = tst;
1819     }
1820     return rc;
1821 }
1822
1823
1824
1825 /*
1826  * FsProcessStart() -- create and start a fs bosserver instance.
1827  *
1828  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1829  */
1830 static int
1831 FsProcessStart(void *bosHandle, const char *instance,
1832                const char *fileserverExe, const char *volserverExe,
1833                const char *salvagerExe, afs_status_p st)
1834 {
1835     int rc = 1;
1836     afs_status_t tst2, tst = 0;
1837
1838     if (!bos_FSProcessCreate
1839         (bosHandle, (char *)instance, (char *)fileserverExe, (char *)volserverExe, (char *)salvagerExe, NULL,
1840          &tst2) && tst2 != BZEXISTS) {
1841         /* failed to create instance (and not because existed) */
1842         tst = tst2;
1843     } else
1844         if (!bos_ProcessExecutionStateSet
1845             (bosHandle, instance, BOS_PROCESS_RUNNING, &tst2)) {
1846         /* failed to set instance state to running */
1847         tst = tst2;
1848     }
1849
1850     if (tst != 0) {
1851         /* indicate failure */
1852         rc = 0;
1853     }
1854     if (st != NULL) {
1855         *st = tst;
1856     }
1857     return rc;
1858 }
1859
1860
1861
1862 /*
1863  * BosProcessDelete() -- stop and delete a bosserver instance, if it exists.
1864  *
1865  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1866  */
1867 static int
1868 BosProcessDelete(void *bosHandle, const char *instance, afs_status_p st)
1869 {
1870     int rc = 1;
1871     afs_status_t tst2, tst = 0;
1872
1873     if (!bos_ProcessExecutionStateSet
1874         (bosHandle, instance, BOS_PROCESS_STOPPED, &tst2)) {
1875         /* failed to set instance state to stopped (or does not exist) */
1876         if (tst2 != BZNOENT) {
1877             tst = tst2;
1878         }
1879
1880     } else if (!bos_ProcessAllWaitTransition(bosHandle, &tst2)) {
1881         /* failed to wait for process to stop */
1882         tst = tst2;
1883
1884     } else if (!bos_ProcessDelete(bosHandle, (char *)instance, &tst2)) {
1885         /* failed to delete instance (or does not exist) */
1886         if (tst2 != BZNOENT) {
1887             tst = tst2;
1888         }
1889     }
1890
1891     if (tst != 0) {
1892         /* indicate failure */
1893         rc = 0;
1894     }
1895     if (st != NULL) {
1896         *st = tst;
1897     }
1898     return rc;
1899 }
1900
1901
1902 /*
1903  * UpdateCommandParse() -- Parse an upserver or upclient command to determine:
1904  *         1) if it explicitly exports/imports the system control directory
1905  *         2) if it explicitly exports/imports the binary directory
1906  *
1907  *    NOTE: cmdString altered (made all lower case and forward slashes)
1908  */
1909 static void
1910 UpdateCommandParse(char *cmdString, short *hasSysPathP, short *hasBinPathP)
1911 {
1912     char *argp, *dirp;
1913
1914     *hasSysPathP = *hasBinPathP = 0;
1915
1916     /* make command string all lower case and forward slashes */
1917
1918     for (argp = cmdString; *argp != '\0'; argp++) {
1919         if (isupper(*argp)) {
1920             *argp = tolower(*argp);
1921         } else if (*argp == '\\') {
1922             *argp = '/';
1923         }
1924     }
1925
1926     /* find end of update executable path (and hence beginning of arguments */
1927
1928     argp = cmdString;
1929
1930     while (isspace(*argp)) {
1931         argp++;
1932     }
1933     while (*argp != '\0' && !isspace(*argp)) {
1934         argp++;
1935     }
1936
1937     /* search for well-known system control directory */
1938
1939     dirp = strstr(argp, AFSDIR_CANONICAL_SERVER_ETC_DIRPATH);
1940
1941     if (dirp != NULL) {
1942         /* check that not a portition of a larger path */
1943         char oneBefore, oneAfter;
1944         char twoAfter = 0;
1945
1946         oneBefore = *(dirp - 1);
1947         oneAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_ETC_DIRPATH) - 1);
1948
1949         if (oneAfter != '\0') {
1950             twoAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_ETC_DIRPATH));
1951         }
1952
1953         if (isspace(oneBefore)) {
1954             if ((isspace(oneAfter)) || (oneAfter == '\0')
1955                 || (oneAfter == '/'
1956                     && (isspace(twoAfter) || twoAfter == '\0'))) {
1957                 *hasSysPathP = 1;
1958             }
1959         }
1960     }
1961
1962     /* search for well-known binary directory */
1963
1964     dirp = strstr(argp, AFSDIR_CANONICAL_SERVER_BIN_DIRPATH);
1965
1966     if (dirp != NULL) {
1967         /* check that not a portition of a larger path */
1968         char oneBefore, oneAfter;
1969         char twoAfter = 0;
1970
1971         oneBefore = *(dirp - 1);
1972         oneAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_BIN_DIRPATH) - 1);
1973
1974         if (oneAfter != '\0') {
1975             twoAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_BIN_DIRPATH));
1976         }
1977
1978         if (isspace(oneBefore)) {
1979             if ((isspace(oneAfter)) || (oneAfter == '\0')
1980                 || (oneAfter == '/'
1981                     && (isspace(twoAfter) || twoAfter == '\0'))) {
1982                 *hasBinPathP = 1;
1983             }
1984         }
1985     }
1986 }
1987
1988
1989
1990 /*
1991  * UbikQuorumCheck() -- Determine if Ubik has achieved quorum for a specified
1992  *     database instance in host's cell.
1993  *
1994  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1995  */
1996 static int
1997 UbikQuorumCheck(cfg_host_p cfg_host, const char *dbInstance, short *hasQuorum,
1998                 afs_status_p st)
1999 {
2000     int rc = 1;
2001     afs_status_t tst2, tst = 0;
2002     void *dbIter;
2003
2004     *hasQuorum = 0;
2005
2006     if (!bos_HostGetBegin(cfg_host->bosHandle, &dbIter, &tst2)) {
2007         tst = tst2;
2008     } else {
2009         /* iterate over server CellServDb, looking for dbserver sync site */
2010         char dbhostName[BOS_MAX_NAME_LEN];
2011         int dbhostAddr;
2012         unsigned short dbhostPort = 0;
2013         int dbhostDone = 0;
2014         int dbhostQueries = 0;
2015
2016         if (!strcmp(dbInstance, KASERVER_BOSNAME)) {
2017             dbhostPort = AFSCONF_KAUTHPORT;
2018         } else if (!strcmp(dbInstance, PTSERVER_BOSNAME)) {
2019             dbhostPort = AFSCONF_PROTPORT;
2020         } else if (!strcmp(dbInstance, VLSERVER_BOSNAME)) {
2021             dbhostPort = AFSCONF_VLDBPORT;
2022         } else if (!strcmp(dbInstance, BUSERVER_BOSNAME)) {
2023             dbhostPort = AFSCONF_BUDBPORT;
2024         }
2025
2026         while (!dbhostDone) {
2027             if (!bos_HostGetNext(dbIter, dbhostName, &tst2)) {
2028                 /* no more entries (or failure) */
2029                 if (tst2 == ADMITERATORDONE) {
2030                     if (dbhostQueries == 0) {
2031                         /* consider quorum to have been achieved when no
2032                          * database servers in cell; otherwise higher-level
2033                          * functions will timeout and fail.
2034                          */
2035                         *hasQuorum = 1;
2036                     }
2037                 } else {
2038                     tst = tst2;
2039                 }
2040                 dbhostDone = 1;
2041
2042             } else
2043                 if (!util_AdminServerAddressGetFromName
2044                     (dbhostName, &dbhostAddr, &tst2)) {
2045                 tst = tst2;
2046                 dbhostDone = 1;
2047             } else {
2048                 short isSyncSite = 0;
2049                 short isWriteReady = 0;
2050
2051                 /* ignore errors fetching Ubik vote status; there might be
2052                  * an unreachable dbserver yet a reachable sync site.
2053                  */
2054                 dbhostQueries++;
2055
2056                 if (UbikVoteStatusFetch
2057                     (dbhostAddr, dbhostPort, &isSyncSite, &isWriteReady,
2058                      &tst2)) {
2059                     /* have quorum if is sync site AND is ready for updates */
2060                     if (isSyncSite) {
2061                         if (isWriteReady) {
2062                             *hasQuorum = 1;
2063                         }
2064                         dbhostDone = 1;
2065                     }
2066                 }
2067             }
2068         }
2069
2070         if (!bos_HostGetDone(dbIter, &tst2)) {
2071             tst = tst2;
2072         }
2073     }
2074
2075     if (tst != 0) {
2076         /* indicate failure */
2077         rc = 0;
2078     }
2079     if (st != NULL) {
2080         *st = tst;
2081     }
2082     return rc;
2083 }
2084
2085
2086 /*
2087  * UbikVoteStatusFetch() -- Fetch Ubik vote status parameters of interest from
2088  *     specified server and port.
2089  *
2090  * RETURN CODES: 1 success, 0 failure  (st indicates why)
2091  */
2092 static int
2093 UbikVoteStatusFetch(int serverAddr, unsigned short serverPort,
2094                     short *isSyncSite, short *isWriteReady, afs_status_p st)
2095 {
2096     int rc = 1;
2097     afs_status_t tst = 0;
2098     struct rx_securityClass *nullSecurity;
2099     struct rx_connection *serverConn;
2100
2101     nullSecurity = rxnull_NewClientSecurityObject();    /* never fails */
2102
2103     if ((serverConn =
2104          rx_GetCachedConnection(htonl(serverAddr), htons(serverPort),
2105                                 VOTE_SERVICE_ID, nullSecurity, 0)) == NULL) {
2106         tst = ADMCFGUBIKVOTENOCONNECTION;
2107     } else {
2108         int rpcCode;
2109         struct ubik_debug udebugInfo;
2110
2111         if ((rpcCode = VOTE_Debug(serverConn, &udebugInfo)) == 0) {
2112             /* talking to a 3.5 or later server */
2113             *isSyncSite = (udebugInfo.amSyncSite ? 1 : 0);
2114             *isWriteReady = 0;
2115
2116             if (*isSyncSite) {
2117                 /* as of 3.5 the database is writeable if "labeled" or if all
2118                  * prior recovery states have been achieved; see defect 9477.
2119                  */
2120                 if (((udebugInfo.recoveryState & UBIK_RECLABELDB))
2121                     || ((udebugInfo.recoveryState & UBIK_RECSYNCSITE)
2122                         && (udebugInfo.recoveryState & UBIK_RECFOUNDDB)
2123                         && (udebugInfo.recoveryState & UBIK_RECHAVEDB))) {
2124                     *isWriteReady = 1;
2125                 }
2126             }
2127
2128         } else if (rpcCode == RXGEN_OPCODE) {
2129             /* talking to old (pre 3.5) server */
2130             struct ubik_debug_old udebugInfo;
2131
2132             if ((rpcCode = VOTE_DebugOld(serverConn, &udebugInfo)) == 0) {
2133                 *isSyncSite = (udebugInfo.amSyncSite ? 1 : 0);
2134                 *isWriteReady = 0;
2135
2136                 if (*isSyncSite) {
2137                     /* pre 3.5 the database is writeable only if "labeled" */
2138                     if (udebugInfo.recoveryState & UBIK_RECLABELDB) {
2139                         *isWriteReady = 1;
2140                     }
2141                 }
2142             }
2143         }
2144
2145         (void)rx_ReleaseCachedConnection(serverConn);
2146
2147         tst = rpcCode;
2148     }
2149
2150     if (tst != 0) {
2151         /* indicate failure */
2152         rc = 0;
2153     }
2154     if (st != NULL) {
2155         *st = tst;
2156     }
2157     return rc;
2158 }