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