bozo: Add KeyFileExt and rxkad.keytab to access rights check
[openafs.git] / src / util / dirpath.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14 #include <afs/opr.h>
15
16 #include <stddef.h>
17 #include <ctype.h>
18 #include <limits.h>
19
20 #include "afsutil.h"
21 #include "fileutil.h"
22
23 #include <afs/opr.h>
24
25 #ifdef AFS_PTHREAD_ENV
26 #include <pthread.h>
27 static pthread_once_t dirInit_once = PTHREAD_ONCE_INIT;
28 #endif
29
30 #ifdef AFS_NT40_ENV
31 #include <WINNT\afssw.h>
32 #endif
33
34 /* local vars */
35 /* static storage for path strings */
36 static char dirPathArray[AFSDIR_PATHSTRING_MAX][AFSDIR_PATH_MAX];
37
38 /* indicate if and how the dirpath module initialized. */
39 static int initFlag = 0;
40 static unsigned int initStatus = 0;
41
42
43 /* storage for dynamically-determined install dir (NT only; long and short) */
44 #ifdef AFS_NT40_ENV
45 static char ntServerInstallDirLong[AFSDIR_PATH_MAX];
46 static char ntServerInstallDirShort[AFSDIR_PATH_MAX];
47 static char ntClientConfigDirLong[AFSDIR_PATH_MAX];
48 static char ntClientConfigDirShort[AFSDIR_PATH_MAX];
49 #endif
50
51 /* storage for local afs server/client paths (top-level) */
52 static char afsSrvDirPath[AFSDIR_PATH_MAX];
53 static char afsClntDirPath[AFSDIR_PATH_MAX];
54
55 /* internal array init function */
56 static void initDirPathArray(void);
57
58 /* Additional macros for ease of use */
59 /* buf is expected to be atleast AFS_PATH_MAX bytes long */
60 #define AFSDIR_SERVER_DIRPATH(buf, dir)  \
61             (void) strcompose(buf, AFSDIR_PATH_MAX, serverPrefix, dir, (char *)NULL)
62
63 #define AFSDIR_SERVER_FILEPATH(buf, dir, file)  \
64             (void) strcompose(buf, AFSDIR_PATH_MAX, serverPrefix, dir, "/", file,  (char *)NULL)
65
66 #define AFSDIR_CLIENT_DIRPATH(buf, dir)  \
67             (void) strcompose(buf, AFSDIR_PATH_MAX, clientPrefix, dir, (char *)NULL)
68
69 #define AFSDIR_CLIENT_FILEPATH(buf, dir, file)  \
70             (void) strcompose(buf, AFSDIR_PATH_MAX,  clientPrefix, dir, "/", file,  (char *)NULL)
71
72
73 /* initAFSDirPath() -- External users call this function to initialize
74  * the dirpath module and/or to determine the initialization status.
75  */
76 unsigned int
77 initAFSDirPath(void)
78 {
79     if (initFlag == 0) {        /* not yet init'ed, so initialize */
80 #ifdef AFS_PTHREAD_ENV
81         pthread_once(&dirInit_once, initDirPathArray);
82 #else
83         initDirPathArray();
84 #endif
85     }
86     return initStatus;
87 }
88
89
90 /* initDirPathArray() -- Initializes the afs dir paths for the
91  *     server and client installations.
92  *
93  *     For NT these are determined dynamically; for Unix they are static.
94  *
95  *     NT NOTE: If a particular component (client/server) is not installed
96  *              then we may not be able to initialize the paths to anything
97  *              meaningful.  In this case the paths are set to the local
98  *              temp directory to avoid later reference to an uninitialized
99  *              variable.  The initStatus flag is set to indicate which
100  *              paths (client/server) initialized properly for callers of
101  *              initAFSDirPath() who would like to know this information.
102  */
103 static void
104 initDirPathArray(void)
105 {
106     char *pathp, *clntEtcDir;
107     const char *clientPrefix = "";
108     const char *serverPrefix = "";
109
110 #ifdef AFS_NT40_ENV
111     char *buf;
112     int status;
113
114     /* get the afs server software installation dir from the registry */
115     if (afssw_GetServerInstallDir(&buf)) {
116         /* failed; server not installed; use temp directory */
117         strcpy(ntServerInstallDirLong, gettmpdir());
118     } else {
119         strcpy(ntServerInstallDirLong, buf);
120         free(buf);
121         initStatus |= AFSDIR_SERVER_PATHS_OK;
122     }
123     FilepathNormalize(ntServerInstallDirLong);
124     status =
125         GetShortPathName(ntServerInstallDirLong, ntServerInstallDirShort,
126                          AFSDIR_PATH_MAX);
127     if (status == 0 || status > AFSDIR_PATH_MAX) {
128         /* can't convert path to short version; just use long version */
129         strcpy(ntServerInstallDirShort, ntServerInstallDirLong);
130     }
131     FilepathNormalize(ntServerInstallDirShort);
132
133     /* get the afs client configuration directory (/usr/vice/etc equivalent) */
134     if (afssw_GetClientCellServDBDir(&buf)) {
135         /* failed */
136         status = GetWindowsDirectory(ntClientConfigDirLong, AFSDIR_PATH_MAX);
137         if (status == 0 || status > AFSDIR_PATH_MAX) {
138             /* failed to get canonical Windows directory; use temp directory */
139             strcpy(ntClientConfigDirLong, gettmpdir());
140         } else {
141             initStatus |= AFSDIR_CLIENT_PATHS_OK;
142         }
143     } else {
144         strcpy(ntClientConfigDirLong, buf);
145         free(buf);
146         initStatus |= AFSDIR_CLIENT_PATHS_OK;
147     }
148     FilepathNormalize(ntClientConfigDirLong);
149
150     status =
151         GetShortPathName(ntClientConfigDirLong, ntClientConfigDirShort,
152                          AFSDIR_PATH_MAX);
153     if (status == 0 || status > AFSDIR_PATH_MAX) {
154         /* can't convert path to short version; just use long version */
155         strcpy(ntClientConfigDirShort, ntClientConfigDirLong);
156     }
157     FilepathNormalize(ntClientConfigDirShort);
158     clientPrefix = ntClientConfigDirShort;
159
160     /* setup the root server directory path (/usr/afs equivalent) */
161     strcpy(afsSrvDirPath, ntServerInstallDirShort);
162     strcat(afsSrvDirPath, AFSDIR_CANONICAL_SERVER_AFS_DIRPATH);
163
164     /* there is no root client directory path (/usr/vice equivalent) */
165     afsClntDirPath[0] = '\0';
166
167     /* setup top level dirpath (/usr equivalent); valid for server ONLY */
168     strcpy(dirPathArray[AFSDIR_USR_DIRPATH_ID], ntServerInstallDirShort);
169     serverPrefix = ntServerInstallDirShort;
170     strcat(dirPathArray[AFSDIR_USR_DIRPATH_ID], AFSDIR_CANONICAL_USR_DIRPATH);
171
172 #else /* AFS_NT40_ENV */
173     /* setup the root server directory path */
174     strcpy(afsSrvDirPath, AFSDIR_CANONICAL_SERVER_AFS_DIRPATH);
175
176     /* setup the root client directory path */
177 #ifdef AFS_DARWIN_ENV
178     if (access(AFSDIR_ALTERNATE_CLIENT_VICE_DIRPATH, F_OK) == 0)
179         strcpy(afsClntDirPath, AFSDIR_ALTERNATE_CLIENT_VICE_DIRPATH);
180     else
181 #endif
182         strcpy(afsClntDirPath, AFSDIR_CANONICAL_CLIENT_VICE_DIRPATH);
183
184     /* setup top level dirpath; valid for both server and client */
185     strcpy(dirPathArray[AFSDIR_USR_DIRPATH_ID], AFSDIR_CANONICAL_USR_DIRPATH);
186
187     initStatus |= (AFSDIR_CLIENT_PATHS_OK | AFSDIR_SERVER_PATHS_OK);
188 #endif /* AFS_NT40_ENV */
189
190     /* now initialize various dir and file paths exported by dirpath module */
191
192     /* server dir paths */
193     strcpy(dirPathArray[AFSDIR_SERVER_AFS_DIRPATH_ID], afsSrvDirPath);
194
195     pathp = dirPathArray[AFSDIR_SERVER_ETC_DIRPATH_ID];
196     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_SERVER_ETC_DIR);
197
198     pathp = dirPathArray[AFSDIR_SERVER_BIN_DIRPATH_ID];
199     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_SERVER_BIN_DIR);
200
201     pathp = dirPathArray[AFSDIR_SERVER_CORES_DIRPATH_ID];
202     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_CORES_DIR);
203
204     pathp = dirPathArray[AFSDIR_SERVER_DB_DIRPATH_ID];
205     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_DB_DIR);
206
207     pathp = dirPathArray[AFSDIR_SERVER_LOGS_DIRPATH_ID];
208     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_LOGS_DIR);
209
210     pathp = dirPathArray[AFSDIR_SERVER_LOCAL_DIRPATH_ID];
211     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_LOCAL_DIR);
212
213     pathp = dirPathArray[AFSDIR_SERVER_BACKUP_DIRPATH_ID];
214     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_BACKUP_DIR);
215
216     pathp = dirPathArray[AFSDIR_SERVER_MIGRATE_DIRPATH_ID];
217     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_MIGR_DIR);
218
219     pathp = dirPathArray[AFSDIR_SERVER_BIN_FILE_DIRPATH_ID];
220     AFSDIR_SERVER_DIRPATH(pathp, AFSDIR_BIN_FILE_DIR);
221
222     /* client dir path */
223 #ifdef AFS_NT40_ENV
224     strcpy(dirPathArray[AFSDIR_CLIENT_VICE_DIRPATH_ID],
225            "/NoUsrViceDirectoryOnWindows");
226     strcpy(dirPathArray[AFSDIR_CLIENT_ETC_DIRPATH_ID],
227            ntClientConfigDirShort);
228
229     clntEtcDir = pathp = dirPathArray[AFSDIR_CLIENT_ETC_DIRPATH_ID];
230 #else
231     strcpy(dirPathArray[AFSDIR_CLIENT_VICE_DIRPATH_ID], afsClntDirPath);
232
233     clntEtcDir = pathp = dirPathArray[AFSDIR_CLIENT_ETC_DIRPATH_ID];
234 #ifdef AFS_DARWIN_ENV
235     if (access(AFSDIR_ALTERNATE_CLIENT_ETC_DIR, F_OK) == 0)
236         AFSDIR_CLIENT_DIRPATH(pathp, AFSDIR_ALTERNATE_CLIENT_ETC_DIR);
237     else
238 #endif
239         AFSDIR_CLIENT_DIRPATH(pathp, AFSDIR_CLIENT_ETC_DIR);
240 #endif /* AFS_NT40_ENV */
241
242 #ifndef AFS_NT40_ENV
243     pathp = dirPathArray[AFSDIR_CLIENT_DATA_DIRPATH_ID];
244 #ifdef AFS_DARWIN_ENV
245     if (access(AFSDIR_ALTERNATE_CLIENT_DATA_DIR, F_OK) == 0)
246         AFSDIR_CLIENT_DIRPATH(pathp, AFSDIR_ALTERNATE_CLIENT_DATA_DIR);
247     else
248 #endif
249         AFSDIR_CLIENT_DIRPATH(pathp, AFSDIR_DATA_DIR);
250 #endif
251
252     /* server file paths */
253     pathp = dirPathArray[AFSDIR_SERVER_THISCELL_FILEPATH_ID];
254     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR,
255                            AFSDIR_THISCELL_FILE);
256
257     pathp = dirPathArray[AFSDIR_SERVER_CELLSERVDB_FILEPATH_ID];
258     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR,
259                            AFSDIR_CELLSERVDB_FILE);
260
261     pathp = dirPathArray[AFSDIR_SERVER_NOAUTH_FILEPATH_ID];
262     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_NOAUTH_FILE);
263
264     pathp = dirPathArray[AFSDIR_SERVER_BUDBLOG_FILEPATH_ID];
265     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_BUDBLOG_FILE);
266
267     pathp = dirPathArray[AFSDIR_SERVER_TAPECONFIG_FILEPATH_ID];
268     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BACKUP_DIR, AFSDIR_TAPECONFIG_FILE);
269
270     pathp = dirPathArray[AFSDIR_SERVER_KALOGDB_FILEPATH_ID];
271     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_KALOGDB_FILE);
272
273     pathp = dirPathArray[AFSDIR_SERVER_KALOG_FILEPATH_ID];
274     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_KALOG_FILE);
275
276     pathp = dirPathArray[AFSDIR_SERVER_KADB_FILEPATH_ID];
277     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_DB_DIR, AFSDIR_KADB_FILE);
278
279     pathp = dirPathArray[AFSDIR_SERVER_NTPD_FILEPATH_ID];
280     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR, AFSDIR_NTPD_FILE);
281
282     pathp = dirPathArray[AFSDIR_SERVER_PRDB_FILEPATH_ID];
283     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_DB_DIR, AFSDIR_PRDB_FILE);
284
285     pathp = dirPathArray[AFSDIR_SERVER_PTLOG_FILEPATH_ID];
286     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_PTLOG_FILE);
287
288     pathp = dirPathArray[AFSDIR_SERVER_KCONF_FILEPATH_ID];
289     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KCONF_FILE);
290
291     pathp = dirPathArray[AFSDIR_SERVER_VLDB_FILEPATH_ID];
292     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_DB_DIR, AFSDIR_VLDB_FILE);
293
294     pathp = dirPathArray[AFSDIR_SERVER_VLOG_FILEPATH_ID];
295     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_VLOG_FILE);
296
297     pathp = dirPathArray[AFSDIR_SERVER_CORELOG_FILEPATH_ID];
298     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_CORE_FILE);
299
300     pathp = dirPathArray[AFSDIR_SERVER_SLVGLOG_FILEPATH_ID];
301     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_SLVGLOG_FILE);
302
303     pathp = dirPathArray[AFSDIR_SERVER_SALSRVLOG_FILEPATH_ID];
304     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_SALSRVLOG_FILE);
305
306     pathp = dirPathArray[AFSDIR_SERVER_SALVAGER_FILEPATH_ID];
307     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR,
308                            AFSDIR_SALVAGER_FILE);
309
310     pathp = dirPathArray[AFSDIR_SERVER_SALSRV_FILEPATH_ID];
311     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_BIN_DIR,
312                            AFSDIR_SALSRV_FILE);
313
314     pathp = dirPathArray[AFSDIR_SERVER_SLVGLOCK_FILEPATH_ID];
315     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_SLVGLOCK_FILE);
316
317     pathp = dirPathArray[AFSDIR_SERVER_KEY_FILEPATH_ID];
318     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KEY_FILE);
319
320     pathp = dirPathArray[AFSDIR_SERVER_ULIST_FILEPATH_ID];
321     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_ULIST_FILE);
322
323     pathp = dirPathArray[AFSDIR_SERVER_BOZCONF_FILEPATH_ID];
324     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSCONFIG_DIR, AFSDIR_BOZCONF_FILE);
325
326     pathp = dirPathArray[AFSDIR_SERVER_BOZCONFNEW_FILEPATH_ID];
327     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSCONFIG_DIR,
328                            AFSDIR_BOZCONFNEW_FILE);
329
330     pathp = dirPathArray[AFSDIR_SERVER_BOZLOG_FILEPATH_ID];
331     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_BOZLOG_FILE);
332
333     pathp = dirPathArray[AFSDIR_SERVER_BOZINIT_FILEPATH_ID];
334     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSCONFIG_DIR, AFSDIR_BOZINIT_FILE);
335
336     pathp = dirPathArray[AFSDIR_SERVER_BOZRXBIND_FILEPATH_ID];
337     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSCONFIG_DIR, AFSDIR_BOZRXBIND_FILE);
338
339     pathp = dirPathArray[AFSDIR_SERVER_BOSVR_FILEPATH_ID];
340     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_BOSSERVER_DIR, AFSDIR_BOSVR_FILE);
341
342     pathp = dirPathArray[AFSDIR_SERVER_VOLSERLOG_FILEPATH_ID];
343     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_VOLSERLOG_FILE);
344
345     pathp = dirPathArray[AFSDIR_SERVER_ROOTVOL_FILEPATH_ID];
346     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_ROOTVOL_FILE);
347
348     pathp = dirPathArray[AFSDIR_SERVER_HOSTDUMP_FILEPATH_ID];
349     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_HOSTDUMP_FILE);
350
351     pathp = dirPathArray[AFSDIR_SERVER_CLNTDUMP_FILEPATH_ID];
352     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_CLNTDUMP_FILE);
353
354     pathp = dirPathArray[AFSDIR_SERVER_CBKDUMP_FILEPATH_ID];
355     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_CBKDUMP_FILE);
356
357     pathp = dirPathArray[AFSDIR_SERVER_OLDSYSID_FILEPATH_ID];
358     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_OLDSYSID_FILE);
359
360     pathp = dirPathArray[AFSDIR_SERVER_SYSID_FILEPATH_ID];
361     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_SYSID_FILE);
362
363     pathp = dirPathArray[AFSDIR_SERVER_FILELOG_FILEPATH_ID];
364     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOGS_DIR, AFSDIR_FILELOG_FILE);
365
366     pathp = dirPathArray[AFSDIR_SERVER_AUDIT_FILEPATH_ID];
367     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_AUDIT_FILE);
368
369     pathp = dirPathArray[AFSDIR_SERVER_CONFIG_FILE_FILEPATH_ID];
370     AFSDIR_CLIENT_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR,
371                            AFSDIR_SERVER_CONFIG_FILE);
372
373     pathp = dirPathArray[AFSDIR_SERVER_NETINFO_FILEPATH_ID];
374     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_NETINFO_FILE);
375
376     pathp = dirPathArray[AFSDIR_SERVER_NETRESTRICT_FILEPATH_ID];
377     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_NETRESTRICT_FILE);
378
379     pathp = dirPathArray[AFSDIR_SERVER_WEIGHTING_CONSTANTS_FILEPATH_ID];
380     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_MIGR_DIR,
381                            AFSDIR_WEIGHTINGCONST_FILE);
382
383     pathp = dirPathArray[AFSDIR_SERVER_THRESHOLD_CONSTANTS_FILEPATH_ID];
384     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_MIGR_DIR,
385                            AFSDIR_THRESHOLDCONST_FILE);
386
387     pathp = dirPathArray[AFSDIR_SERVER_MIGRATELOG_FILEPATH_ID];
388     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_MIGR_DIR, AFSDIR_MIGRATE_LOGNAME);
389
390     pathp = dirPathArray[AFSDIR_SERVER_KRB_EXCL_FILEPATH_ID];
391     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_KRB_EXCL_FILE);
392
393     pathp = dirPathArray[AFSDIR_SERVER_FSSTATE_FILEPATH_ID];
394     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_LOCAL_DIR, AFSDIR_FSSTATE_FILE);
395
396     pathp = dirPathArray[AFSDIR_SERVER_RXKAD_KEYTAB_FILEPATH_ID];
397     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_RXKAD_KEYTAB_FILE);
398
399     pathp = dirPathArray[AFSDIR_SERVER_EXT_KEY_FILEPATH_ID];
400     AFSDIR_SERVER_FILEPATH(pathp, AFSDIR_SERVER_ETC_DIR, AFSDIR_EXT_KEY_FILE);
401
402     /* client file paths */
403 #ifdef AFS_NT40_ENV
404     strcpy(dirPathArray[AFSDIR_CLIENT_THISCELL_FILEPATH_ID],
405            "/NoUsrViceEtcThisCellFileOnWindows");
406     sprintf(dirPathArray[AFSDIR_CLIENT_CELLSERVDB_FILEPATH_ID], "%s/%s",
407             ntClientConfigDirShort, AFSDIR_CELLSERVDB_FILE_NTCLIENT);
408     strcpy(dirPathArray[AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID],
409            "/NoCellAliasOnWindows");
410 #else
411     pathp = dirPathArray[AFSDIR_CLIENT_THISCELL_FILEPATH_ID];
412     AFSDIR_CLIENT_FILEPATH(pathp, clntEtcDir, AFSDIR_THISCELL_FILE);
413
414     pathp = dirPathArray[AFSDIR_CLIENT_CELLSERVDB_FILEPATH_ID];
415     AFSDIR_CLIENT_FILEPATH(pathp, clntEtcDir, AFSDIR_CELLSERVDB_FILE);
416
417     pathp = dirPathArray[AFSDIR_CLIENT_CELLALIAS_FILEPATH_ID];
418     AFSDIR_CLIENT_FILEPATH(pathp, clntEtcDir, AFSDIR_CELLALIAS_FILE);
419 #endif /* AFS_NT40_ENV */
420
421     pathp = dirPathArray[AFSDIR_CLIENT_CONFIG_FILE_FILEPATH_ID];
422     AFSDIR_CLIENT_FILEPATH(pathp, clntEtcDir, AFSDIR_CLIENT_CONFIG_FILE);
423
424     pathp = dirPathArray[AFSDIR_CLIENT_NETINFO_FILEPATH_ID];
425     AFSDIR_CLIENT_FILEPATH(pathp, clntEtcDir, AFSDIR_NETINFO_FILE);
426
427     pathp = dirPathArray[AFSDIR_CLIENT_NETRESTRICT_FILEPATH_ID];
428     AFSDIR_CLIENT_FILEPATH(pathp, clntEtcDir, AFSDIR_NETRESTRICT_FILE);
429
430     initFlag = 1;               /* finished dirpath initialization */
431     return;
432 }
433
434 /* afs_getDirPath - returns a const char pointer to the requested string
435  * from the internal path array.
436  * string_id - index into the path array
437  */
438 const char *
439 afs_getDirPath(afsdir_id_t string_id)
440 {
441     /* check if the array has been initialized */
442     if (initFlag == 0) {        /* no it's not, so initialize */
443 #ifdef AFS_PTHREAD_ENV
444         pthread_once(&dirInit_once, initDirPathArray);
445 #else
446         initDirPathArray();
447 #endif
448     }
449     return (const char *)dirPathArray[string_id];
450 }
451
452 #ifdef AFS_NT40_ENV
453 /* getDirPath - present for ABI compatibility on Windows systems;
454  * Unix systems should not use it. */
455 const char *
456 getDirPath(afsdir_id_t string_id)
457 {
458     return afs_getDirPath(string_id);
459 }
460 #endif
461
462 /*
463  * LocalizePathHead() -- Make path relative to local part
464  *
465  * ConstructLocalPath takes a path and a directory that path should
466  * be considered relative to.  There are two possible cases:
467  *
468  * The path is an absolute path.  In this case, the relative path
469  * is ignored.  We check the path for a prefix that represents a
470  * canonical path, and if one is found, we adjust the path to remove
471  * the prefix and adjust the directory to which it should be
472  * considered relative to be the local version of that canonical path.
473  *
474  * The path is a relative path.  In this case, we check to see if the
475  * directory to which it is relative represents a canonical path, and
476  * if so, we adjust that directory to be the local version of that
477  * canonical path.  The relative path itself is left unchanged.
478  */
479
480 /* The following array  maps cannonical parts to local parts.  It
481  * might  seem reasonable to  simply construct an array in parallel to
482  * dirpatharray  but it turns out you don't want translations for all
483  * local paths.
484 */
485
486 struct canonmapping {
487     const char *canonical;
488     const char *local;
489 };
490 static struct canonmapping CanonicalTranslations[] = {
491     {AFSDIR_CANONICAL_SERVER_ETC_DIRPATH, AFSDIR_SERVER_ETC_DIR},
492     {AFSDIR_CANONICAL_SERVER_LOGS_DIRPATH, AFSDIR_LOGS_DIR},
493     {AFSDIR_CANONICAL_SERVER_LOCAL_DIRPATH, AFSDIR_LOCAL_DIR},
494     {AFSDIR_CANONICAL_SERVER_BIN_DIRPATH, AFSDIR_SERVER_BIN_DIR},
495     {NULL, NULL}
496 };
497
498 static void
499 LocalizePathHead(const char **path, const char **relativeTo)
500 {
501      struct canonmapping *map;
502
503      if (**path == '/') {
504          for (map = CanonicalTranslations; map->local != NULL; map++) {
505              int canonlength = strlen(map->canonical);
506              if (strncmp(*path, map->canonical, canonlength) == 0) {
507                  (*path) += canonlength;
508                  if (**path == '/')
509                      (*path)++;
510                  *relativeTo = map->local;
511                  return;
512              }
513          }
514      } else {
515          for (map = CanonicalTranslations; map->local != NULL; map++) {
516              if (strcmp(*relativeTo, map->canonical) == 0) {
517                  *relativeTo = map->local;
518                  return;
519              }
520          }
521      }
522 }
523
524
525 #ifdef AFS_NT40_ENV
526 /* NT version of ConstructLocalPath() */
527
528 /*
529  * ConstructLocalPath() --  Convert a canonical (wire-format) path to a fully
530  *     specified local path.  Upon successful completion, *fullPathBufp is
531  *     set to an allocated buffer containing the fully specified local path
532  *     constructed from the cpath argument.
533  *
534  *     On NT, path construction proceeds as follows:
535  *         1) If cpath is fully qualified (i.e., starts with 'X:/') then the
536  *            path returned is equivalent to cpath.
537  *         2) If cpath begins with a drive letter but is not fully qualified,
538  *            i.e., it is drive relative, then the function fails with EINVAL.
539  *         3) If cpath begins with '/' (or '\') then the path returned is the
540  *            concatenation  AFS-server-install-dir + cpath after translating for localization.
541  *         4) Otherwise the path returned is the concatenation
542  *            AFS-server-install-dir + relativeTo + cpath.
543  *
544  *     Leading whitespace in cpath is ignored; the constructed path is
545  *     normalized (FilepathNormalize()).
546  *
547  * RETURN CODES: 0 if successful; errno code otherwise.
548  */
549 int
550 ConstructLocalPath(const char *cpath, const char *relativeTo,
551                    char **fullPathBufp)
552 {
553     int status = 0;
554     char *newPath = NULL;
555
556     if (initFlag == 0) {        /* dirpath module not yet initialized */
557 #ifdef AFS_PTHREAD_ENV
558         pthread_once(&dirInit_once, initDirPathArray);
559 #else
560         initDirPathArray();
561 #endif
562     }
563
564     *fullPathBufp = NULL;
565
566     if (cpath == NULL)
567         return ENOENT;
568
569     while (isspace(*cpath)) {
570         cpath++;
571     }
572
573     LocalizePathHead(&cpath, &relativeTo);
574     if ((((*cpath >= 'a') && (*cpath <= 'z'))
575          || ((*cpath >= 'A') && (*cpath <= 'Z'))) && (*(cpath + 1) == ':')) {
576
577         /* cpath has a leading drive letter */
578         if ((*(cpath + 2) != '/') && (*(cpath + 2) != '\\')) {
579             /* drive letter relative path; this is not allowed */
580             status = EINVAL;
581         } else {
582             /* fully qualified path; just make a copy */
583             newPath = strdup(cpath);
584             if (!newPath)
585                 status = ENOMEM;
586         }
587
588     } else {
589         /* cpath has NO leading drive letter; make relative to install dir */
590         size_t pathSize = strlen(ntServerInstallDirShort) + 2;
591
592         if ((*cpath == '/') || (*cpath == '\\')) {
593             /* construct path relative to install directory only */
594             pathSize += strlen(cpath);
595
596             newPath = malloc(pathSize);
597             if (!newPath) {
598                 status = ENOMEM;
599             } else {
600                 sprintf(newPath, "%s/%s", ntServerInstallDirShort, cpath);
601             }
602         } else {
603             /* construct path relative to 'relativeTo' (and install dir) */
604             pathSize += strlen(relativeTo) + 1 + strlen(cpath);
605
606             newPath = malloc(pathSize);
607             if (!newPath) {
608                 status = ENOMEM;
609             } else {
610                 sprintf(newPath, "%s/%s/%s", ntServerInstallDirShort,
611                         relativeTo, cpath);
612             }
613         }
614     }
615
616     if (status == 0) {
617         FilepathNormalize(newPath);
618
619         /* return buffer containing fully specified path */
620         *fullPathBufp = newPath;
621     }
622
623     return status;
624 }
625
626 #else
627 /* Unix version of ConstructLocalPath() */
628
629 /*
630  * ConstructLocalPath() --  Convert a canonical (wire-format) path to a fully
631  *     specified local path.  Upon successful completion, *fullPathBufp is
632  *     set to an allocated buffer containing the fully specified local path
633  *     constructed from the cpath argument.
634  *
635  *     On Unix, path construction proceeds as follows:
636  *         1) If cpath begins with '/' then the path returned is equivalent
637  *            to cpath.
638  *         2) Otherwise the path returned is the concatenation
639  *            relativeTo + cpath.
640  *
641  *     Leading whitespace in cpath is ignored; the constructed path is
642  *     normalized (FilepathNormalize()).
643  *
644  * RETURN CODES: 0 if successful; errno code otherwise.
645  */
646 int
647 ConstructLocalPath(const char *cpath, const char *relativeTo,
648                    char **fullPathBufp)
649 {
650     int status = 0;
651     char *newPath = NULL;
652
653     if (initFlag == 0) {        /* dirpath module not yet initialized */
654 #ifdef AFS_PTHREAD_ENV
655         pthread_once(&dirInit_once, initDirPathArray);
656 #else
657         initDirPathArray();
658 #endif
659     }
660
661     *fullPathBufp = NULL;
662
663     if (cpath == NULL)
664         return ENOENT;
665
666     while (isspace(*cpath)) {
667         cpath++;
668     }
669
670     LocalizePathHead(&cpath, &relativeTo);
671     if (*cpath == '/') {
672         newPath = strdup(cpath);
673     } else {
674         if (asprintf(&newPath, "%s/%s", relativeTo, cpath) < 0)
675             newPath = NULL;
676     }
677     if (newPath == NULL)
678         status = ENOMEM;
679
680     if (status == 0) {
681         FilepathNormalize(newPath);
682
683         /* return buffer containing fully specified path */
684         *fullPathBufp = newPath;
685     }
686
687     return status;
688 }
689 #endif /* AFS_NT40_ENV */
690
691
692 /*
693  * ConstructLocalBinPath() -- A convenience wrapper for ConstructLocalPath()
694  *     that specifies the canonical AFS server binary directory as the relative
695  *     directory.
696  */
697 int
698 ConstructLocalBinPath(const char *cpath, char **fullPathBufp)
699 {
700     return ConstructLocalPath(cpath, AFSDIR_SERVER_BIN_DIRPATH,
701                               fullPathBufp);
702 }
703
704
705 /*
706  * ConstructLocalLogPath() -- A convenience wrapper for ConstructLocalPath()
707  *     that specifies the canonical AFS server logs directory as the relative
708  *     directory.
709  */
710 int
711 ConstructLocalLogPath(const char *cpath, char **fullPathBufp)
712 {
713     return ConstructLocalPath(cpath, AFSDIR_SERVER_LOGS_DIRPATH,
714                               fullPathBufp);
715 }