Fix misspelling of writable as writeable
[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 argsBuf[AFSDIR_PATH_MAX], *args;
1169         size_t argsLen = 0;
1170
1171         if (exportClear != NULL && *exportClear != '\0') {
1172             argsLen += strlen("-clear ") + strlen(exportClear) + 1;
1173         }
1174         if (exportCrypt != NULL && *exportCrypt != '\0') {
1175             argsLen += strlen("-crypt ") + strlen(exportCrypt) + 1;
1176         }
1177
1178         if (argsLen == 0) {
1179             args = NULL;
1180         } else {
1181             if (argsLen <= AFSDIR_PATH_MAX) {
1182                 args = argsBuf;
1183             } else {
1184                 args = (char *)malloc(argsLen);
1185             }
1186
1187             if (args == NULL) {
1188                 tst = ADMNOMEM;
1189             } else {
1190                 if (exportClear == NULL) {
1191                     sprintf(args, "-crypt %s", exportCrypt);
1192                 } else if (exportCrypt == NULL) {
1193                     sprintf(args, "-clear %s", exportClear);
1194                 } else {
1195                     sprintf(args, "-clear %s -crypt %s", exportClear,
1196                             exportCrypt);
1197                 }
1198             }
1199         }
1200
1201         if (tst == 0) {
1202             if (!SimpleProcessStart
1203                 (cfg_host->bosHandle, UPSERVER_BOSNAME, UPSERVER_EXEPATH,
1204                  args, &tst2)) {
1205                 tst = tst2;
1206             }
1207
1208             if (args != NULL && args != argsBuf) {
1209                         free(args);
1210             }
1211         }
1212     }
1213
1214     if (tst != 0) {
1215         /* indicate failure */
1216         rc = 0;
1217     }
1218     if (st != NULL) {
1219         *st = tst;
1220     }
1221     return rc;
1222 }
1223
1224
1225 /*
1226  * cfg_UpdateServerStop() -- Stop, and unconfigure, the Update server on host.
1227  */
1228 int ADMINAPI
1229 cfg_UpdateServerStop(void *hostHandle,  /* host config handle */
1230                      afs_status_p st)
1231 {                               /* completion status */
1232     int rc = 1;
1233     afs_status_t tst2, tst = 0;
1234     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1235
1236     /* validate parameters and prepare host handle for bos functions */
1237
1238     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1239         tst = tst2;
1240     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1241         tst = tst2;
1242     }
1243
1244     /* stop and delete upserver instance */
1245
1246     if (tst == 0) {
1247         if (!BosProcessDelete(cfg_host->bosHandle, UPSERVER_BOSNAME, &tst2)) {
1248             tst = tst2;
1249         }
1250     }
1251
1252     if (tst != 0) {
1253         /* indicate failure */
1254         rc = 0;
1255     }
1256     if (st != NULL) {
1257         *st = tst;
1258     }
1259     return rc;
1260 }
1261
1262
1263 /*
1264  * cfg_UpdateServerQueryStatus() -- Query status of Update server on host.
1265  */
1266 int ADMINAPI
1267 cfg_UpdateServerQueryStatus(void *hostHandle,   /* host config handle */
1268                             short *isUpserverP, /* update server configured */
1269                             short *isSysCtrlP,  /* system control configured */
1270                             short *isBinDistP,  /* binary dist configured */
1271                             afs_status_p st)
1272 {                               /* completion status */
1273     int rc = 1;
1274     afs_status_t tst2, tst = 0;
1275     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1276
1277     /* validate parameters and prepare host handle for bos functions */
1278
1279     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1280         tst = tst2;
1281     } else if (isUpserverP == NULL || isSysCtrlP == NULL
1282                || isBinDistP == NULL) {
1283         tst = ADMCFGUPSERVERCONFIGFLAGPNULL;
1284     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1285         tst = tst2;
1286     }
1287
1288     /* query bosserver to determine if, and how, upserver is configured */
1289
1290     if (tst == 0) {
1291         void *cmdIter;
1292
1293         *isUpserverP = *isSysCtrlP = *isBinDistP = 0;
1294
1295         if (!bos_ProcessParameterGetBegin
1296             (cfg_host->bosHandle, UPSERVER_BOSNAME, &cmdIter, &tst2)) {
1297             tst = tst2;
1298         } else {
1299             char cmdString[BOS_MAX_NAME_LEN];
1300
1301             if (!bos_ProcessParameterGetNext(cmdIter, cmdString, &tst2)) {
1302                 /* no upserver instance (or error) */
1303                 if (tst2 != BZNOENT) {
1304                     tst = tst2;
1305                 }
1306             } else {
1307                 /* parse upserver command line to determine how configured */
1308                 short hasSysPath, hasBinPath;
1309
1310                 UpdateCommandParse(cmdString, &hasSysPath, &hasBinPath);
1311
1312                 *isUpserverP = 1;
1313
1314                 if (hasSysPath) {
1315                     *isSysCtrlP = 1;
1316                 }
1317                 if (hasBinPath) {
1318                     *isBinDistP = 1;
1319                 }
1320             }
1321
1322             if (!bos_ProcessParameterGetDone(cmdIter, &tst2)) {
1323                 tst = tst2;
1324             }
1325         }
1326     }
1327
1328     if (tst != 0) {
1329         /* indicate failure */
1330         rc = 0;
1331     }
1332     if (st != NULL) {
1333         *st = tst;
1334     }
1335     return rc;
1336 }
1337
1338
1339 /*
1340  * cfg_SysBinServerStart() -- Start Update server in System Control and/or
1341  *     Binary Distribution machine configuration on host.
1342  *
1343  *     This function is a convenience wrapper for cfg_UpdateServerStart().
1344  */
1345 int ADMINAPI
1346 cfg_SysBinServerStart(void *hostHandle, /* host config handle */
1347                       short makeSysCtrl,        /* config as sys control mach */
1348                       short makeBinDist,        /* config as binary dist mach */
1349                       afs_status_p st)
1350 {                               /* completion status */
1351     char *cryptSysDir = NULL;
1352     char *clearBinDir = NULL;
1353
1354     if (makeSysCtrl) {
1355         cryptSysDir = AFSDIR_CANONICAL_SERVER_ETC_DIRPATH;
1356     }
1357
1358     if (makeBinDist) {
1359         clearBinDir = AFSDIR_CANONICAL_SERVER_BIN_DIRPATH;
1360     }
1361
1362     return cfg_UpdateServerStart(hostHandle, clearBinDir, cryptSysDir, st);
1363 }
1364
1365
1366
1367 /* ---------------- Exported Update Client functions ------------------ */
1368
1369
1370
1371 /*
1372  * cfg_UpdateClientStart() -- Start an Update client on host.
1373  *
1374  *     Argument string import specifies a set of space-separated directories
1375  *     to import.  Argument frequency specifies the import interval in
1376  *     seconds; if the value is zero (0) then the default frequency is used.
1377  *
1378  *     The BOS instance name used is the concatenation of the string constant
1379  *     cfg_upclientBosNamePrefix and the argument string bosSuffix.
1380  */
1381 int ADMINAPI
1382 cfg_UpdateClientStart(void *hostHandle, /* host config handle */
1383                       const char *bosSuffix,    /* BOS instance suffix */
1384                       const char *upserver,     /* upserver to import from */
1385                       short crypt,      /* import encrypted */
1386                       const char *import,       /* dirs to import */
1387                       unsigned int frequency,   /* import interval in sec. */
1388                       afs_status_p st)
1389 {                               /* completion status */
1390     int rc = 1;
1391     afs_status_t tst2, tst = 0;
1392     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1393     char upclientInstance[BOS_MAX_NAME_LEN];
1394
1395     /* validate parameters and prepare host handle for bos functions */
1396
1397     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1398         tst = tst2;
1399     } else if (bosSuffix == NULL) {
1400         tst = ADMCFGUPCLIENTSUFFIXNULL;
1401     } else if ((strlen(UPCLIENT_BOSNAME) + strlen(bosSuffix) + 1) >
1402                BOS_MAX_NAME_LEN) {
1403         tst = ADMCFGUPCLIENTSUFFIXTOOLONG;
1404     } else if (upserver == NULL || *upserver == '\0') {
1405         tst = ADMCFGUPCLIENTTARGETSERVERNULL;
1406     } else if (import == NULL || *import == '\0') {
1407         tst = ADMCFGUPCLIENTIMPORTDIRNULL;
1408     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1409         tst = tst2;
1410     }
1411
1412     /* stop and delete existing update client instance, if any.
1413      * we do this because the set of imported directores might be changing.
1414      */
1415
1416     if (tst == 0) {
1417         sprintf(upclientInstance, "%s%s", UPCLIENT_BOSNAME, bosSuffix);
1418
1419         if (!BosProcessDelete(cfg_host->bosHandle, upclientInstance, &tst2)) {
1420             tst = tst2;
1421         }
1422     }
1423
1424     /* create and start update client instance */
1425
1426     if (tst == 0) {
1427         char argsBuf[AFSDIR_PATH_MAX], *args;
1428         size_t argsLen = 0;
1429
1430         argsLen += strlen(upserver) + 1;
1431
1432         if (crypt) {
1433             argsLen += strlen("-crypt ");
1434         } else {
1435             argsLen += strlen("-clear ");
1436         }
1437
1438         if (frequency != 0) {
1439             argsLen += strlen("-t ") + 10 /* max uint */  + 1;
1440         }
1441
1442         argsLen += strlen(import) + 1;
1443
1444         if (argsLen <= AFSDIR_PATH_MAX) {
1445             args = argsBuf;
1446         } else {
1447             args = (char *)malloc(argsLen);
1448         }
1449
1450         if (args == NULL) {
1451             tst = ADMNOMEM;
1452         } else {
1453             /* set up argument buffer */
1454             if (crypt) {
1455                 sprintf(args, "%s -crypt ", upserver);
1456             } else {
1457                 sprintf(args, "%s -clear ", upserver);
1458             }
1459             if (frequency != 0) {
1460                 char *strp = args + strlen(args);
1461                 sprintf(strp, "-t %u ", frequency);
1462             }
1463             strcat(args, import);
1464
1465             /* create and start instance */
1466             if (!SimpleProcessStart
1467                 (cfg_host->bosHandle, upclientInstance, UPCLIENT_EXEPATH,
1468                  args, &tst2)) {
1469                 tst = tst2;
1470             }
1471
1472             if (args != argsBuf) {
1473                         free(args);
1474             }
1475         }
1476     }
1477
1478     if (tst != 0) {
1479         /* indicate failure */
1480         rc = 0;
1481     }
1482     if (st != NULL) {
1483         *st = tst;
1484     }
1485     return rc;
1486 }
1487
1488
1489 /*
1490  * cfg_UpdateClientStop() -- Stop, and unconfigure, an Update client on host.
1491  */
1492 int ADMINAPI
1493 cfg_UpdateClientStop(void *hostHandle,  /* host config handle */
1494                      const char *bosSuffix,     /* BOS instance suffix */
1495                      afs_status_p st)
1496 {                               /* completion status */
1497     int rc = 1;
1498     afs_status_t tst2, tst = 0;
1499     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1500     char upclientInstance[BOS_MAX_NAME_LEN];
1501
1502     /* validate parameters and prepare host handle for bos functions */
1503
1504     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1505         tst = tst2;
1506     } else if (bosSuffix == NULL) {
1507         tst = ADMCFGUPCLIENTSUFFIXNULL;
1508     } else if ((strlen(UPCLIENT_BOSNAME) + strlen(bosSuffix) + 1) >
1509                BOS_MAX_NAME_LEN) {
1510         tst = ADMCFGUPCLIENTSUFFIXTOOLONG;
1511     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1512         tst = tst2;
1513     }
1514
1515     /* stop and delete specified update client instance */
1516
1517     if (tst == 0) {
1518         sprintf(upclientInstance, "%s%s", UPCLIENT_BOSNAME, bosSuffix);
1519
1520         if (!BosProcessDelete(cfg_host->bosHandle, upclientInstance, &tst2)) {
1521             tst = tst2;
1522         }
1523     }
1524
1525     if (tst != 0) {
1526         /* indicate failure */
1527         rc = 0;
1528     }
1529     if (st != NULL) {
1530         *st = tst;
1531     }
1532     return rc;
1533 }
1534
1535
1536 /*
1537  * cfg_UpdateClientStopAll() -- Stop, and unconfigure, all Update clients
1538  *     on host.
1539  */
1540 int ADMINAPI
1541 cfg_UpdateClientStopAll(void *hostHandle,       /* host config handle */
1542                         afs_status_p st)
1543 {                               /* completion status */
1544     int rc = 1;
1545     afs_status_t tst2, tst = 0;
1546     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1547
1548     /* validate parameters and prepare host handle for bos functions */
1549
1550     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1551         tst = tst2;
1552     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1553         tst = tst2;
1554     }
1555
1556     /* find, stop, and delete all update client instances */
1557
1558     if (tst == 0) {
1559         void *procIter;
1560
1561         if (!bos_ProcessNameGetBegin(cfg_host->bosHandle, &procIter, &tst2)) {
1562             tst = tst2;
1563         } else {
1564             /* iterate over process names, looking for update clients */
1565             char procName[BOS_MAX_NAME_LEN];
1566             int procDone = 0;
1567
1568             while (!procDone) {
1569                 if (!bos_ProcessNameGetNext(procIter, procName, &tst2)) {
1570                     /* no more processes (or failure) */
1571                     if (tst2 != ADMITERATORDONE) {
1572                         tst = tst2;
1573                     }
1574                     procDone = 1;
1575
1576                 } else
1577                     if (!strncmp
1578                         (UPCLIENT_BOSNAME, procName,
1579                          (sizeof(UPCLIENT_BOSNAME) - 1))) {
1580                     /* upclient instance prefix; assume is upclient */
1581                     if (!BosProcessDelete
1582                         (cfg_host->bosHandle, procName, &tst2)) {
1583                         tst = tst2;
1584                         procDone = 1;
1585                     }
1586                 }
1587             }
1588
1589             if (!bos_ProcessNameGetDone(procIter, &tst2)) {
1590                 tst = tst2;
1591             }
1592         }
1593     }
1594
1595     if (tst != 0) {
1596         /* indicate failure */
1597         rc = 0;
1598     }
1599     if (st != NULL) {
1600         *st = tst;
1601     }
1602     return rc;
1603 }
1604
1605
1606 /*
1607  * cfg_UpdateClientQueryStatus() -- Query status of Update clients on host.
1608  */
1609 int ADMINAPI
1610 cfg_UpdateClientQueryStatus(void *hostHandle,   /* host config handle */
1611                             short *isUpclientP, /* an upclient is configured */
1612                             short *isSysP,      /* system control client */
1613                             short *isBinP,      /* binary dist. client */
1614                             afs_status_p st)
1615 {                               /* completion status */
1616     int rc = 1;
1617     afs_status_t tst2, tst = 0;
1618     cfg_host_p cfg_host = (cfg_host_p) hostHandle;
1619
1620     /* validate parameters and prepare host handle for bos functions */
1621
1622     if (!cfgutil_HostHandleValidate(cfg_host, &tst2)) {
1623         tst = tst2;
1624     } else if (isUpclientP == NULL || isSysP == NULL || isBinP == NULL) {
1625         tst = ADMCFGUPCLIENTCONFIGFLAGPNULL;
1626     } else if (!cfgutil_HostHandleBosInit(cfg_host, &tst2)) {
1627         tst = tst2;
1628     }
1629
1630     /* determine if, and how, any upclients are configured */
1631
1632     if (tst == 0) {
1633         void *procIter;
1634
1635         *isUpclientP = *isSysP = *isBinP = 0;
1636
1637         if (!bos_ProcessNameGetBegin(cfg_host->bosHandle, &procIter, &tst2)) {
1638             tst = tst2;
1639         } else {
1640             /* iterate over process names, looking for update clients */
1641             char procName[BOS_MAX_NAME_LEN];
1642             int procDone = 0;
1643
1644             while (!procDone) {
1645                 if (!bos_ProcessNameGetNext(procIter, procName, &tst2)) {
1646                     /* no more processes (or failure) */
1647                     if (tst2 != ADMITERATORDONE) {
1648                         tst = tst2;
1649                     }
1650                     procDone = 1;
1651
1652                 } else
1653                     if (!strncmp
1654                         (UPCLIENT_BOSNAME, procName,
1655                          (sizeof(UPCLIENT_BOSNAME) - 1))) {
1656                     /* upclient instance prefix; assume is upclient */
1657                     void *cmdIter;
1658
1659                     *isUpclientP = 1;
1660
1661                     if (!bos_ProcessParameterGetBegin
1662                         (cfg_host->bosHandle, procName, &cmdIter, &tst2)) {
1663                         tst = tst2;
1664                     } else {
1665                         char cmdString[BOS_MAX_NAME_LEN];
1666
1667                         if (!bos_ProcessParameterGetNext
1668                             (cmdIter, cmdString, &tst2)) {
1669                             /* instance deleted out from under us (or error) */
1670                             if (tst2 != BZNOENT) {
1671                                 tst = tst2;
1672                             }
1673                         } else {
1674                             /* parse command line to determine how config */
1675                             short hasSysPath, hasBinPath;
1676
1677                             UpdateCommandParse(cmdString, &hasSysPath,
1678                                                &hasBinPath);
1679
1680                             if (hasSysPath) {
1681                                 *isSysP = 1;
1682                             }
1683                             if (hasBinPath) {
1684                                 *isBinP = 1;
1685                             }
1686                         }
1687
1688                         if (!bos_ProcessParameterGetDone(cmdIter, &tst2)) {
1689                             tst = tst2;
1690                         }
1691                     }
1692
1693                     if (tst != 0) {
1694                         procDone = 1;
1695                     }
1696                 }
1697             }                   /* while() */
1698
1699             if (!bos_ProcessNameGetDone(procIter, &tst2)) {
1700                 tst = tst2;
1701             }
1702         }
1703     }
1704
1705     if (tst != 0) {
1706         /* indicate failure */
1707         rc = 0;
1708     }
1709     if (st != NULL) {
1710         *st = tst;
1711     }
1712     return rc;
1713 }
1714
1715
1716 /*
1717  * cfg_SysControlClientStart() -- Start an Update client in System Control
1718  *     client configuration on host.
1719  *
1720  *     This function is a convenience wrapper for cfg_UpdateClientStart().
1721  *     The BOS instance suffix used is the constant cfg_upclientSysBosSuffix.
1722  */
1723 int ADMINAPI
1724 cfg_SysControlClientStart(void *hostHandle,     /* host config handle */
1725                           const char *upserver, /* upserver to import from */
1726                           afs_status_p st)
1727 {                               /* completion status */
1728     return cfg_UpdateClientStart(hostHandle, cfg_upclientSysBosSuffix,
1729                                  upserver, 1 /* crypt */ ,
1730                                  AFSDIR_CANONICAL_SERVER_ETC_DIRPATH,
1731                                  0 /* default frequency */ ,
1732                                  st);
1733 }
1734
1735
1736 /*
1737  * cfg_BinDistClientStart() -- Start an Update client in Binary Distribution
1738  *     client configuration on host.
1739  *
1740  *     This function is a convenience wrapper for cfg_UpdateClientStart().
1741  *     The BOS instance suffix used is the constant cfg_upclientBinBosSuffix.
1742  */
1743 int ADMINAPI
1744 cfg_BinDistClientStart(void *hostHandle,        /* host config handle */
1745                        const char *upserver,    /* upserver to import from */
1746                        afs_status_p st)
1747 {                               /* completion status */
1748     return cfg_UpdateClientStart(hostHandle, cfg_upclientBinBosSuffix,
1749                                  upserver, 0 /* crypt */ ,
1750                                  AFSDIR_CANONICAL_SERVER_BIN_DIRPATH,
1751                                  0 /* default frequency */ ,
1752                                  st);
1753 }
1754
1755
1756
1757 /* ---------------- Local functions ------------------ */
1758
1759 /*
1760  * SimpleProcessStart() -- create and start a simple bosserver instance.
1761  *
1762  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1763  */
1764 static int
1765 SimpleProcessStart(void *bosHandle, const char *instance,
1766                    const char *executable, const char *args, afs_status_p st)
1767 {
1768     int rc = 1;
1769     afs_status_t tst2, tst = 0;
1770     char cmdBuf[AFSDIR_PATH_MAX], *cmd;
1771     size_t cmdLen;
1772
1773     cmdLen = strlen(executable) + 1 + (args == NULL ? 0 : (strlen(args) + 1));
1774
1775     if (cmdLen <= AFSDIR_PATH_MAX) {
1776         cmd = cmdBuf;
1777     } else {
1778         cmd = (char *)malloc(cmdLen);
1779     }
1780
1781     if (cmd == NULL) {
1782         tst = ADMNOMEM;
1783     } else {
1784         if (args == NULL) {
1785             strcpy(cmd, executable);
1786         } else {
1787             sprintf(cmd, "%s %s", executable, args);
1788         }
1789
1790         if (!bos_ProcessCreate
1791             (bosHandle, (char *)instance, BOS_PROCESS_SIMPLE, cmd, NULL, NULL, &tst2)
1792             && tst2 != BZEXISTS) {
1793             /* failed to create instance (and not because existed) */
1794             tst = tst2;
1795         } else
1796             if (!bos_ProcessExecutionStateSet
1797                 (bosHandle, (char *)instance, BOS_PROCESS_RUNNING, &tst2)) {
1798             /* failed to set instance state to running */
1799             tst = tst2;
1800         }
1801
1802         if (cmd != cmdBuf) {
1803             free(cmd);
1804         }
1805     }
1806
1807     if (tst != 0) {
1808         /* indicate failure */
1809         rc = 0;
1810     }
1811     if (st != NULL) {
1812         *st = tst;
1813     }
1814     return rc;
1815 }
1816
1817
1818
1819 /*
1820  * FsProcessStart() -- create and start a fs bosserver instance.
1821  *
1822  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1823  */
1824 static int
1825 FsProcessStart(void *bosHandle, const char *instance,
1826                const char *fileserverExe, const char *volserverExe,
1827                const char *salvagerExe, afs_status_p st)
1828 {
1829     int rc = 1;
1830     afs_status_t tst2, tst = 0;
1831
1832     if (!bos_FSProcessCreate
1833         (bosHandle, (char *)instance, (char *)fileserverExe, (char *)volserverExe, (char *)salvagerExe, NULL,
1834          &tst2) && tst2 != BZEXISTS) {
1835         /* failed to create instance (and not because existed) */
1836         tst = tst2;
1837     } else
1838         if (!bos_ProcessExecutionStateSet
1839             (bosHandle, instance, BOS_PROCESS_RUNNING, &tst2)) {
1840         /* failed to set instance state to running */
1841         tst = tst2;
1842     }
1843
1844     if (tst != 0) {
1845         /* indicate failure */
1846         rc = 0;
1847     }
1848     if (st != NULL) {
1849         *st = tst;
1850     }
1851     return rc;
1852 }
1853
1854
1855
1856 /*
1857  * BosProcessDelete() -- stop and delete a bosserver instance, if it exists.
1858  *
1859  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1860  */
1861 static int
1862 BosProcessDelete(void *bosHandle, const char *instance, afs_status_p st)
1863 {
1864     int rc = 1;
1865     afs_status_t tst2, tst = 0;
1866
1867     if (!bos_ProcessExecutionStateSet
1868         (bosHandle, instance, BOS_PROCESS_STOPPED, &tst2)) {
1869         /* failed to set instance state to stopped (or does not exist) */
1870         if (tst2 != BZNOENT) {
1871             tst = tst2;
1872         }
1873
1874     } else if (!bos_ProcessAllWaitTransition(bosHandle, &tst2)) {
1875         /* failed to wait for process to stop */
1876         tst = tst2;
1877
1878     } else if (!bos_ProcessDelete(bosHandle, (char *)instance, &tst2)) {
1879         /* failed to delete instance (or does not exist) */
1880         if (tst2 != BZNOENT) {
1881             tst = tst2;
1882         }
1883     }
1884
1885     if (tst != 0) {
1886         /* indicate failure */
1887         rc = 0;
1888     }
1889     if (st != NULL) {
1890         *st = tst;
1891     }
1892     return rc;
1893 }
1894
1895
1896 /*
1897  * UpdateCommandParse() -- Parse an upserver or upclient command to determine:
1898  *         1) if it explicitly exports/imports the system control directory
1899  *         2) if it explicitly exports/imports the binary directory
1900  *
1901  *    NOTE: cmdString altered (made all lower case and forward slashes)
1902  */
1903 static void
1904 UpdateCommandParse(char *cmdString, short *hasSysPathP, short *hasBinPathP)
1905 {
1906     char *argp, *dirp;
1907
1908     *hasSysPathP = *hasBinPathP = 0;
1909
1910     /* make command string all lower case and forward slashes */
1911
1912     for (argp = cmdString; *argp != '\0'; argp++) {
1913         if (isupper(*argp)) {
1914             *argp = tolower(*argp);
1915         } else if (*argp == '\\') {
1916             *argp = '/';
1917         }
1918     }
1919
1920     /* find end of update executable path (and hence beginning of arguments */
1921
1922     argp = cmdString;
1923
1924     while (isspace(*argp)) {
1925         argp++;
1926     }
1927     while (*argp != '\0' && !isspace(*argp)) {
1928         argp++;
1929     }
1930
1931     /* search for well-known system control directory */
1932
1933     dirp = strstr(argp, AFSDIR_CANONICAL_SERVER_ETC_DIRPATH);
1934
1935     if (dirp != NULL) {
1936         /* check that not a portition of a larger path */
1937         char oneBefore, oneAfter;
1938         char twoAfter = 0;
1939
1940         oneBefore = *(dirp - 1);
1941         oneAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_ETC_DIRPATH) - 1);
1942
1943         if (oneAfter != '\0') {
1944             twoAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_ETC_DIRPATH));
1945         }
1946
1947         if (isspace(oneBefore)) {
1948             if ((isspace(oneAfter)) || (oneAfter == '\0')
1949                 || (oneAfter == '/'
1950                     && (isspace(twoAfter) || twoAfter == '\0'))) {
1951                 *hasSysPathP = 1;
1952             }
1953         }
1954     }
1955
1956     /* search for well-known binary directory */
1957
1958     dirp = strstr(argp, AFSDIR_CANONICAL_SERVER_BIN_DIRPATH);
1959
1960     if (dirp != NULL) {
1961         /* check that not a portition of a larger path */
1962         char oneBefore, oneAfter;
1963         char twoAfter = 0;
1964
1965         oneBefore = *(dirp - 1);
1966         oneAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_BIN_DIRPATH) - 1);
1967
1968         if (oneAfter != '\0') {
1969             twoAfter = *(dirp + sizeof(AFSDIR_CANONICAL_SERVER_BIN_DIRPATH));
1970         }
1971
1972         if (isspace(oneBefore)) {
1973             if ((isspace(oneAfter)) || (oneAfter == '\0')
1974                 || (oneAfter == '/'
1975                     && (isspace(twoAfter) || twoAfter == '\0'))) {
1976                 *hasBinPathP = 1;
1977             }
1978         }
1979     }
1980 }
1981
1982
1983
1984 /*
1985  * UbikQuorumCheck() -- Determine if Ubik has achieved quorum for a specified
1986  *     database instance in host's cell.
1987  *
1988  * RETURN CODES: 1 success, 0 failure  (st indicates why)
1989  */
1990 static int
1991 UbikQuorumCheck(cfg_host_p cfg_host, const char *dbInstance, short *hasQuorum,
1992                 afs_status_p st)
1993 {
1994     int rc = 1;
1995     afs_status_t tst2, tst = 0;
1996     void *dbIter;
1997
1998     *hasQuorum = 0;
1999
2000     if (!bos_HostGetBegin(cfg_host->bosHandle, &dbIter, &tst2)) {
2001         tst = tst2;
2002     } else {
2003         /* iterate over server CellServDb, looking for dbserver sync site */
2004         char dbhostName[BOS_MAX_NAME_LEN];
2005         int dbhostAddr;
2006         unsigned short dbhostPort = 0;
2007         int dbhostDone = 0;
2008         int dbhostQueries = 0;
2009
2010         if (!strcmp(dbInstance, KASERVER_BOSNAME)) {
2011             dbhostPort = AFSCONF_KAUTHPORT;
2012         } else if (!strcmp(dbInstance, PTSERVER_BOSNAME)) {
2013             dbhostPort = AFSCONF_PROTPORT;
2014         } else if (!strcmp(dbInstance, VLSERVER_BOSNAME)) {
2015             dbhostPort = AFSCONF_VLDBPORT;
2016         } else if (!strcmp(dbInstance, BUSERVER_BOSNAME)) {
2017             dbhostPort = AFSCONF_BUDBPORT;
2018         }
2019
2020         while (!dbhostDone) {
2021             if (!bos_HostGetNext(dbIter, dbhostName, &tst2)) {
2022                 /* no more entries (or failure) */
2023                 if (tst2 == ADMITERATORDONE) {
2024                     if (dbhostQueries == 0) {
2025                         /* consider quorum to have been achieved when no
2026                          * database servers in cell; otherwise higher-level
2027                          * functions will timeout and fail.
2028                          */
2029                         *hasQuorum = 1;
2030                     }
2031                 } else {
2032                     tst = tst2;
2033                 }
2034                 dbhostDone = 1;
2035
2036             } else
2037                 if (!util_AdminServerAddressGetFromName
2038                     (dbhostName, &dbhostAddr, &tst2)) {
2039                 tst = tst2;
2040                 dbhostDone = 1;
2041             } else {
2042                 short isSyncSite = 0;
2043                 short isWriteReady = 0;
2044
2045                 /* ignore errors fetching Ubik vote status; there might be
2046                  * an unreachable dbserver yet a reachable sync site.
2047                  */
2048                 dbhostQueries++;
2049
2050                 if (UbikVoteStatusFetch
2051                     (dbhostAddr, dbhostPort, &isSyncSite, &isWriteReady,
2052                      &tst2)) {
2053                     /* have quorum if is sync site AND is ready for updates */
2054                     if (isSyncSite) {
2055                         if (isWriteReady) {
2056                             *hasQuorum = 1;
2057                         }
2058                         dbhostDone = 1;
2059                     }
2060                 }
2061             }
2062         }
2063
2064         if (!bos_HostGetDone(dbIter, &tst2)) {
2065             tst = tst2;
2066         }
2067     }
2068
2069     if (tst != 0) {
2070         /* indicate failure */
2071         rc = 0;
2072     }
2073     if (st != NULL) {
2074         *st = tst;
2075     }
2076     return rc;
2077 }
2078
2079
2080 /*
2081  * UbikVoteStatusFetch() -- Fetch Ubik vote status parameters of interest from
2082  *     specified server and port.
2083  *
2084  * RETURN CODES: 1 success, 0 failure  (st indicates why)
2085  */
2086 static int
2087 UbikVoteStatusFetch(int serverAddr, unsigned short serverPort,
2088                     short *isSyncSite, short *isWriteReady, afs_status_p st)
2089 {
2090     int rc = 1;
2091     afs_status_t tst = 0;
2092     struct rx_securityClass *nullSecurity;
2093     struct rx_connection *serverConn;
2094
2095     nullSecurity = rxnull_NewClientSecurityObject();    /* never fails */
2096
2097     if ((serverConn =
2098          rx_GetCachedConnection(htonl(serverAddr), htons(serverPort),
2099                                 VOTE_SERVICE_ID, nullSecurity, 0)) == NULL) {
2100         tst = ADMCFGUBIKVOTENOCONNECTION;
2101     } else {
2102         int rpcCode;
2103         struct ubik_debug udebugInfo;
2104
2105         if ((rpcCode = VOTE_Debug(serverConn, &udebugInfo)) == 0) {
2106             /* talking to a 3.5 or later server */
2107             *isSyncSite = (udebugInfo.amSyncSite ? 1 : 0);
2108             *isWriteReady = 0;
2109
2110             if (*isSyncSite) {
2111                 /* as of 3.5 the database is writable if "labeled" or if all
2112                  * prior recovery states have been achieved; see defect 9477.
2113                  */
2114                 if (((udebugInfo.recoveryState & UBIK_RECLABELDB))
2115                     || ((udebugInfo.recoveryState & UBIK_RECSYNCSITE)
2116                         && (udebugInfo.recoveryState & UBIK_RECFOUNDDB)
2117                         && (udebugInfo.recoveryState & UBIK_RECHAVEDB))) {
2118                     *isWriteReady = 1;
2119                 }
2120             }
2121
2122         } else if (rpcCode == RXGEN_OPCODE) {
2123             /* talking to old (pre 3.5) server */
2124             struct ubik_debug_old udebugInfo;
2125
2126             if ((rpcCode = VOTE_DebugOld(serverConn, &udebugInfo)) == 0) {
2127                 *isSyncSite = (udebugInfo.amSyncSite ? 1 : 0);
2128                 *isWriteReady = 0;
2129
2130                 if (*isSyncSite) {
2131                     /* pre 3.5 the database is writable only if "labeled" */
2132                     if (udebugInfo.recoveryState & UBIK_RECLABELDB) {
2133                         *isWriteReady = 1;
2134                     }
2135                 }
2136             }
2137         }
2138
2139         (void)rx_ReleaseCachedConnection(serverConn);
2140
2141         tst = rpcCode;
2142     }
2143
2144     if (tst != 0) {
2145         /* indicate failure */
2146         rc = 0;
2147     }
2148     if (st != NULL) {
2149         *st = tst;
2150     }
2151     return rc;
2152 }