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