Initial IBM OpenAFS 1.0 tree
[openafs.git] / src / WINNT / afs_setup_utils / sutil.c
1 /* Copyright (C) 1999 Transarc Corporation - All rights reserved.
2  *
3  */
4
5 #include <afs/param.h>
6 #include <afs/stds.h>
7
8 #include <windows.h>
9 #include <stdlib.h>
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <ctype.h>
14
15 #include <WINNT/afsreg.h>
16
17 #include "sutil.h"
18
19 /* Some install/uninstall related utilities. */
20
21
22 #define NETWORK_PROVIDER_ORDER_KEY      "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order"
23 #define PROVIDER_ORDER_VALUE_NAME       "ProviderOrder"
24
25 #define ENVIRONMENT_KEY                 "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
26
27 #define AUTOEXEC_PATH                   "c:\\autoexec.bat"
28 #define AUTOEXEC_TMP_PATH               "c:\\TaAfsAutoexec.tmp"
29
30
31 static BOOL ReadRegEnv(char **ppszEnvValue, char *pszRegValueName);
32 static BOOL WriteRegEnv(char *pszEnvValue, char *pszEnvName);
33 static BOOL ReadAutoExec(char **ppszEnvValue, char *pszEnvName);
34 static BOOL WriteAutoExec(char *pszEnvValue, char *pszEnvName);
35 static BOOL FindSubString(const char *s1, const char *s2);
36
37
38
39 /* ------------------ exported functions ---------------------- */
40
41 BOOL InNetworkProviderOrder(char *pszNetworkProvider, BOOL *pbIn)
42 {
43     HKEY hKey;
44     LONG bResult;
45     DWORD dwType;
46     char *pszProviderOrder = 0;
47     DWORD dwSize;
48
49         bResult = FALSE;        // Assume failure
50
51     if (RegOpenKeyAlt(AFSREG_NULL_KEY, NETWORK_PROVIDER_ORDER_KEY, KEY_READ, FALSE, &hKey, 0) == ERROR_SUCCESS) {
52         if (RegQueryValueAlt(hKey, PROVIDER_ORDER_VALUE_NAME, &dwType, &pszProviderOrder, &dwSize) == ERROR_SUCCESS) {
53                         *pbIn = strstr(pszProviderOrder, pszNetworkProvider) != 0;
54                         bResult = TRUE;
55                         free(pszProviderOrder);
56                 }
57         RegCloseKey(hKey);
58     }
59
60         return bResult;
61 }
62
63
64 /*
65  * AddToProviderOrder() -- add entry to network provider order
66  */
67 BOOL AddToProviderOrder(char *pszWhatToAdd)
68 {
69     HKEY hKey;
70     DWORD dwType;
71     LONG result;
72     int nLen;
73     char *pszValue = 0;
74     char *pszNewValue;
75     BOOL bAlreadyAdded = FALSE;
76
77     /* Open the key, creating it if necessary (but should always be there). */
78     result = RegOpenKeyAlt(AFSREG_NULL_KEY,
79                            NETWORK_PROVIDER_ORDER_KEY,
80                            KEY_SET_VALUE | KEY_ALL_ACCESS, TRUE, &hKey, 0);
81     if (result != ERROR_SUCCESS)
82         return FALSE;
83
84     /* Get the old value */
85     result = RegQueryValueAlt(hKey,
86                               PROVIDER_ORDER_VALUE_NAME,
87                               &dwType, &pszValue, &nLen);
88     if (result != ERROR_SUCCESS) {
89         nLen = 0;
90     }
91
92     pszNewValue = malloc(nLen + strlen(pszWhatToAdd) + 1);/* Add 1 for comma */
93     *pszNewValue = 0;
94
95     /* Add the new value */
96     if (result == ERROR_SUCCESS) {
97         if (strstr(pszValue, pszWhatToAdd) != 0)
98             bAlreadyAdded = TRUE;
99         else {
100             if (pszValue && *pszValue) {
101                 strcpy(pszNewValue, pszValue);
102                 strcat(pszNewValue, ",");
103             }
104             strcat(pszNewValue, pszWhatToAdd);          
105         }
106
107     } else if (result == ERROR_FILE_NOT_FOUND)
108         strcpy(pszNewValue, pszWhatToAdd);
109
110     /* Set the new value in the registry */
111     if (((result == ERROR_SUCCESS) ||
112          (result == ERROR_FILE_NOT_FOUND)) && !bAlreadyAdded)
113         result = RegSetValueEx(hKey, PROVIDER_ORDER_VALUE_NAME, 0,
114                                REG_SZ, pszNewValue, strlen(pszNewValue) + 1);
115     free(pszNewValue);
116     free(pszValue);
117
118     RegCloseKey(hKey);
119
120     return (result == ERROR_SUCCESS);
121 }
122
123
124 /*
125  * RemoveFromProviderOrder() -- remove entry from network provider order
126  */
127 BOOL RemoveFromProviderOrder(char *pszWhatToDel)
128 {
129     HKEY hKey;
130     DWORD dwType;
131     LONG result;
132     int nLen;
133     char *pszValue = 0;
134     char *pszNewValue;
135     BOOL bAlreadyRemoved = FALSE;
136
137     /* Open the key, creating if necessary (but should always be there). */
138     result = RegOpenKeyAlt(AFSREG_NULL_KEY, NETWORK_PROVIDER_ORDER_KEY,
139                            KEY_SET_VALUE | KEY_ALL_ACCESS, TRUE, &hKey, 0);
140     if (result != ERROR_SUCCESS)
141         return FALSE;
142
143     /* Get the old value */
144     result = RegQueryValueAlt(hKey, PROVIDER_ORDER_VALUE_NAME,
145                               &dwType, &pszValue, &nLen);
146
147     if (result == ERROR_SUCCESS) {
148         pszNewValue = malloc(nLen); /* bigger than we need, but that's ok */
149         *pszNewValue = 0;
150
151         if (strstr(pszValue, pszWhatToDel) == 0)
152             bAlreadyRemoved = TRUE;
153         else {
154             char *pszCur;
155
156             pszCur = strtok(pszValue, ",");
157             while (pszCur) {
158                 if (strcmp(pszCur, pszWhatToDel) != 0) {
159                     if (*pszNewValue)
160                         strcat(pszNewValue, ",");
161                     strcat(pszNewValue, pszCur);
162                 }
163                 pszCur = strtok(0, ",");
164             }
165         }
166
167         /* Set the new value in the registry */
168         if (!bAlreadyRemoved)
169             result = RegSetValueEx(hKey, PROVIDER_ORDER_VALUE_NAME, 0, REG_SZ,
170                                    pszNewValue, strlen(pszNewValue) + 1);
171         free(pszNewValue);
172         free(pszValue);
173     }
174     RegCloseKey(hKey);
175
176     return (result == ERROR_SUCCESS);
177 }
178
179
180 /*
181  * ReadSystemEnv() -- read system environment variable
182  */
183 BOOL ReadSystemEnv(char **ppszEnvValue, char *pszEnvName)
184 {
185     if (IsWinNT())
186         return ReadRegEnv(ppszEnvValue, pszEnvName);
187     else
188         return ReadAutoExec(ppszEnvValue, pszEnvName);
189 }
190
191
192 /*
193  * WriteSystemEnv() -- write system environment variable
194  */
195 BOOL WriteSystemEnv(char *pszEnvValue, char *pszEnvName)
196 {
197     if (IsWinNT())
198         return WriteRegEnv(pszEnvValue, pszEnvName);
199     else
200         return WriteAutoExec(pszEnvValue, pszEnvName);
201 }
202
203
204 /*
205  * AddToSystemPath() -- add specified entry to system PATH variable.
206  */
207 BOOL AddToSystemPath(char *pszPath)
208 {
209     char *pszCurPath = 0;
210     char *pszNewPath = 0;
211     BOOL bStatus = TRUE;
212
213     if (!ReadSystemEnv(&pszCurPath, "Path"))
214         return FALSE;
215
216     /* Do we need to add it? */
217     if (!pszCurPath || !FindSubString(pszCurPath, pszPath)) {
218                 
219         /* Old path + a semicolon + the new path entry + a null */
220         pszNewPath = malloc((pszCurPath ? strlen(pszCurPath) + 1 : 0) +
221                             strlen(pszPath) + 1);
222         if (pszNewPath == 0) {
223             if (pszCurPath)
224                 free(pszCurPath);
225             return FALSE;
226         }
227
228         pszNewPath[0] = 0;
229
230         if (pszCurPath) {
231             strcpy(pszNewPath, pszCurPath);
232             strcat(pszNewPath, ";");
233         }
234
235         strcat(pszNewPath, pszPath);
236         bStatus = WriteSystemEnv(pszNewPath, "Path");
237
238         free(pszNewPath);
239     }
240
241     if (pszCurPath)
242         free(pszCurPath);
243
244     return bStatus;
245 }
246
247
248 /*
249  * RemoveFromSystemPath() -- remove specified entry from system PATH variable.
250  */
251 BOOL RemoveFromSystemPath(char *pszPath)
252 {
253     char *pszCurNls = 0;
254     char *pszNewNls = 0;
255     char *pSemi = 0;
256     char *pCurPath = 0;
257     BOOL bStatus = TRUE;
258
259     if (!ReadSystemEnv(&pszCurNls, "Path"))
260         return FALSE;
261
262     /* Is it already not in the path? */
263     if (!pszCurNls || !FindSubString(pszCurNls, pszPath)) {
264         if (pszCurNls)
265             free(pszCurNls);
266         return TRUE;
267     }
268
269     pszNewNls = (char *)malloc(strlen(pszCurNls) + 1);
270     if (pszNewNls == 0) {
271         free(pszCurNls);
272         return FALSE;
273     }
274
275     pszNewNls[0] = 0;
276
277     pCurPath = pszCurNls;
278
279     while (1) {
280         pSemi = strchr(pCurPath, ';');
281         if (pSemi)
282             *pSemi = 0;
283
284         if (_stricmp(pCurPath, pszPath) != 0) {
285             if (pszNewNls[0] != 0)
286                 strcat(pszNewNls, ";");
287             strcat(pszNewNls, pCurPath);
288         }
289
290         if (!pSemi)
291             break;
292
293         pSemi++;
294         pCurPath = pSemi;
295     }
296
297     bStatus = WriteSystemEnv(pszNewNls, "Path");
298
299     free(pszNewNls);
300     free(pszCurNls);
301
302     return bStatus;
303 }
304
305
306 /*
307  * IsWinNT() -- determine if system is NT or other (95/98).
308  */
309 BOOL IsWinNT()
310 {
311     DWORD dwVersion = GetVersion();
312
313     return (dwVersion < 0x80000000);
314 }
315
316
317
318
319
320
321 /* ------------------ utility functions ---------------------- */
322
323
324 /*
325  * ReadRegEnv() -- read system enviornment variable from registry (NT only).
326  */
327 static BOOL ReadRegEnv(char **ppszEnvValue, char *pszRegValueName)
328 {
329     HKEY hKey;
330     DWORD dwType;
331     LONG result;
332     int nLen = 512;
333
334     result = RegOpenKeyAlt(AFSREG_NULL_KEY, ENVIRONMENT_KEY,
335                            KEY_SET_VALUE | KEY_ALL_ACCESS, FALSE, &hKey, 0);
336     if (result != ERROR_SUCCESS)
337         return FALSE;
338
339     *ppszEnvValue = 0;
340
341     do {
342         if (*ppszEnvValue)
343             free(*ppszEnvValue);
344
345         *ppszEnvValue = (char *)malloc(nLen);
346         if (*ppszEnvValue == 0) {
347             RegCloseKey(hKey);
348             return FALSE;
349         }
350
351         /* If function fails to open the value and the error code says that
352          * the value doesn't exist, then we will attempt to make it.
353          */
354         result = RegQueryValueEx(hKey, pszRegValueName, 0,
355                                  &dwType, *ppszEnvValue, &nLen);
356
357         if (result == ERROR_FILE_NOT_FOUND) {
358             result = RegSetValueEx(hKey, pszRegValueName, 0,
359                                    REG_EXPAND_SZ, "", 0);
360             **ppszEnvValue = '\0';  /* zero length string "read" */
361         }
362     } while (result == ERROR_MORE_DATA);
363
364     RegCloseKey(hKey);
365
366     if (result != ERROR_SUCCESS || strlen(*ppszEnvValue) == 0) {
367         /* Don't return empty strings; instead set buffer pointer to 0. */
368         free(*ppszEnvValue);
369         *ppszEnvValue = 0;
370     }
371     return (result == ERROR_SUCCESS);
372 }
373
374
375 /*
376  * WriteRegEnv() -- write system environment variable to registry (NT only).
377  */
378 static BOOL WriteRegEnv(char *pszEnvValue, char *pszEnvName)
379 {
380     LONG result;
381     HKEY hKey;
382
383     result = RegOpenKeyAlt(AFSREG_NULL_KEY, ENVIRONMENT_KEY,
384                            KEY_ALL_ACCESS, FALSE, &hKey, 0);
385     if (result != ERROR_SUCCESS)
386         return FALSE;
387
388     result = RegSetValueEx(hKey, pszEnvName, 0, REG_EXPAND_SZ,
389                            pszEnvValue, strlen(pszEnvValue) + 1);
390     RegCloseKey(hKey);
391
392     return (result == ERROR_SUCCESS);
393 }
394
395
396 /*
397  * ReadAutoExec() -- read environment variable from autoexec.bat (95/98).
398  */
399 static BOOL ReadAutoExec(char **ppszEnvValue, char *pszEnvName)
400 {
401     char szSetCmd[256];
402     char szLine[2048];
403     FILE *fp;
404
405     *ppszEnvValue = 0;
406
407     fp = fopen(AUTOEXEC_PATH, "rt");
408     if (fp == 0)
409         return FALSE;
410
411     /* Create the string we are looking for */
412     sprintf(szSetCmd, "SET %s", pszEnvName);
413
414     /* Now read each line and look for our SetCmd string */
415     while (1) {
416         int nLineLen;
417         fgets(szLine, sizeof(szLine), fp);
418
419         if (feof(fp))
420             break;
421
422         /* Strip off the trailing newline */
423         nLineLen = strlen(szLine);
424         if (szLine[nLineLen - 1] == '\n') {
425             nLineLen--;
426             szLine[nLineLen] = 0;
427         }
428
429         if (_strnicmp(szSetCmd, szLine, strlen(szSetCmd)) == 0) {
430             char *value = strchr(szLine, '=');
431             if (value)
432                 *ppszEnvValue = _strdup(++value);
433             break;
434         }
435     }
436
437     /* Don't return empty strings; instead set buffer to 0. */
438     if (*ppszEnvValue && (strlen(*ppszEnvValue) == 0)) {
439         free(*ppszEnvValue);
440         *ppszEnvValue = 0;
441     }
442
443     fclose(fp);
444
445     return TRUE;
446 }
447
448
449 /*
450  * WriteAutoExec() -- write environment variable to autoexec.bat (95/98).
451  */
452 static BOOL WriteAutoExec(char *pszEnvValue, char *pszEnvName)
453 {
454     char szSetCmd[256];
455     char szLine[512];
456     BOOL bValueWritten = FALSE;
457     FILE *fpIn, *fpOut;
458     BOOL bResult;
459
460     fpOut = fopen(AUTOEXEC_TMP_PATH, "wt");
461     if (fpOut == 0)
462         return FALSE;
463
464     sprintf(szSetCmd, "SET %s", pszEnvName);
465
466     fpIn = fopen(AUTOEXEC_PATH, "rt");
467     if (fpIn != 0) {
468         /* Now read each line and look for our SetCmd string */
469         while (1) {
470             fgets(szLine, sizeof(szLine), fpIn);
471             if (feof(fpIn))
472                 break;
473
474             if (!bValueWritten &&
475                 (_strnicmp(szSetCmd, szLine, strlen(szSetCmd)) == 0)) {
476                 fprintf(fpOut, "%s=%s\n", szSetCmd, pszEnvValue);
477                 bValueWritten = TRUE;
478             } else
479                 fputs(szLine, fpOut);
480         }
481
482         fclose(fpIn);
483     }
484
485     /* If the value didn't previously exist, then add it to the end */
486     if (!bValueWritten)
487         fprintf(fpOut, "%s=%s\n", szSetCmd, pszEnvValue);
488
489     fclose(fpOut);
490
491     bResult = CopyFile(AUTOEXEC_TMP_PATH, AUTOEXEC_PATH, FALSE);
492
493     /* Try to delete this even if the copy fails.  Tie the return code
494      * to the copy and not the delete.
495      */
496     DeleteFile(AUTOEXEC_TMP_PATH);
497
498     return bResult;
499 }
500
501
502 /*
503  * FindSubString() -- basically a case-insensitive strstr().
504  */
505 static BOOL FindSubString(const char *s1, const char *s2)
506 {
507     char *ls1, *ls2;
508     BOOL bFound = FALSE;
509
510     ls1 = _strdup(s1);
511     if (!ls1)
512         return FALSE;
513
514     ls2 = _strdup(s2);
515     if (!ls2) {
516         free(ls1);
517         return FALSE;
518     }
519
520     bFound = strstr(_strlwr(ls1), _strlwr(ls2)) != 0;
521
522     free(ls2);
523     free(ls1);
524     return bFound;
525 }