afs_snprintf is dead, long live rk_snprintf
[openafs.git] / src / WINNT / afsreg / afssw.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 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <windows.h>
17 #include <shlobj.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stddef.h>
21 #include <string.h>
22 #include <errno.h>
23
24 #include <afs/errmap_nt.h>
25
26 #include "afsreg.h"
27 #include "afssw.h"
28
29 static int
30 StringDataRead(const char *keyName, const char *valueName, char **bufPP);
31
32 static int
33 StringDataWrite(const char *keyName, const char *valueName, const char *data);
34
35 static int
36 DwordDataRead(const char *keyName, const char *valueName, DWORD *data);
37
38
39
40 /* Functions for accessing AFS software configuration information. */
41
42 /*
43  * afssw_GetServerInstallDir() -- Get directory in which AFS server software is
44  *     installed.  Sets *bufPP to point to allocated buffer containing string.
45  *
46  * RETURN CODES: 0 success, -1 failed (errno set)
47  */
48 int
49 afssw_GetServerInstallDir(char **bufPP)  /* [out] data buffer */
50 {
51     return StringDataRead(AFSREG_SVR_SW_VERSION_KEY,
52                           AFSREG_SVR_SW_VERSION_DIR_VALUE,
53                           bufPP);
54 }
55
56
57 /*
58  * afssw_GetClientInstallDir() -- Get directory in which AFS client software is
59  *     installed.  Sets *bufPP to point to allocated buffer containing string.
60  *
61  * RETURN CODES: 0 success, -1 failed (errno set)
62  */
63 int
64 afssw_GetClientInstallDir(char **bufPP)   /* [out] data buffer */
65 {
66     int retval = StringDataRead(AFSREG_CLT_SW_VERSION_KEY,
67                           AFSREG_CLT_SW_VERSION_DIR_VALUE,
68                           bufPP);
69     if (retval)
70         retval = StringDataRead(AFSREG_CLT_TOOLS_SW_VERSION_KEY,
71                           AFSREG_CLT_SW_VERSION_DIR_VALUE,
72                           bufPP);
73     return retval;
74 }
75
76 /*
77  * afssw_GetClientCellServDBDir() -- Get directory in which AFS client CellServDB
78  * file is installed.  Sets *bufPP to point to allocated buffer containing string.
79  *
80  * RETURN CODES: 0 success, -1 failed (errno set)
81  */
82 int
83 afssw_GetClientCellServDBDir(char **bufPP)   /* [out] data buffer */
84 {
85     char wdir[512];
86     int tlen;
87     char *path = NULL;
88     DWORD cbPath;
89
90     cbPath = GetEnvironmentVariable("AFSCONF", NULL, 0);
91     if (cbPath) {
92         cbPath += 2;
93         path = malloc(cbPath);
94         if (path) {
95             GetEnvironmentVariable("AFSCONF", path, cbPath);
96             tlen = (int)strlen(path);
97             if (path[tlen-1] != '\\') {
98                 strncat(path, "\\", cbPath);
99                 path[cbPath-1] = '\0';
100             }
101             *bufPP = path;
102             return 0;
103         }
104     }
105
106     if (!StringDataRead(AFSREG_CLT_OPENAFS_KEY,
107                           AFSREG_CLT_OPENAFS_CELLSERVDB_DIR_VALUE,
108                          &path)) {
109         tlen = (int)strlen(path);
110         if (path[tlen-1] != '\\') {
111             char * newPath = malloc(tlen+2);
112             if (newPath) {
113                 _snprintf(newPath,tlen+2,"%s\\",path);
114                 free(path);
115                 path = newPath;
116             }
117         }
118         *bufPP = path;
119         return 0;
120     }
121
122     /*
123      * Try to find the All Users\Application Data\OpenAFS\Client directory.
124      * If it exists and it contains a CellServDB file, return that. 
125      * Otherwise, return the Install Directory for backward compatibility.
126      * SHGetFolderPath requires wdir to be of length MAX_PATH which is 260.
127      */
128     if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 
129                                     SHGFP_TYPE_CURRENT, wdir)))
130     {   HANDLE fh;
131
132         tlen = (int)strlen(wdir);
133         if (wdir[tlen-1] != '\\') {
134             strncat(wdir, "\\", sizeof(wdir));
135             wdir[sizeof(wdir)-1] = '\0';
136             tlen++;
137         }
138         strncat(wdir, "OpenAFS\\Client\\CellServDB", sizeof(wdir)); 
139         wdir[sizeof(wdir)-1] = '\0';
140
141         fh = CreateFile(wdir, GENERIC_READ, FILE_SHARE_READ, NULL, 
142                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
143         if (fh != INVALID_HANDLE_VALUE) {
144             CloseHandle(fh);
145             tlen += (int)strlen("OpenAFS\\Client\\");
146             wdir[tlen] = '\0';
147             *bufPP = strdup(wdir);
148             return 0;
149         }
150     }
151
152     return afssw_GetClientInstallDir(bufPP);
153 }
154
155
156 /*
157  * afssw_GetClientCellName() -- Get name of cell in which AFS client is
158  *     configured.  Sets *bufPP to point to allocated buffer containing string.
159  *
160  * RETURN CODES: 0 success, -1 failed (errno set)
161  */
162 int
163 afssw_GetClientCellName(char **bufPP)  /* [out] data buffer */
164 {
165     return StringDataRead(AFSREG_CLT_SVC_PARAM_KEY,
166                           AFSREG_CLT_SVC_PARAM_CELL_VALUE,
167                           bufPP);
168 }
169
170
171 /*
172  * afssw_SetClientCellName() -- Set name of cell in which AFS client is
173  *     configured.
174  *
175  * RETURN CODES: 0 success, -1 failed (errno set)
176  */
177 int
178 afssw_SetClientCellName(const char *cellName)
179 {
180     return StringDataWrite(AFSREG_CLT_SVC_PARAM_KEY,
181                            AFSREG_CLT_SVC_PARAM_CELL_VALUE,
182                            cellName);
183 }
184
185
186 /*
187  * afssw_GetServerVersion() -- Get version number of installed server.
188  *
189  * RETURN CODES: 0 success, -1 failed (errno set)
190  */
191 int
192 afssw_GetServerVersion(unsigned *major,  /* major version number */
193                        unsigned *minor,  /* minor version number */
194                        unsigned *patch)  /* patch level */
195 {
196     DWORD dwMajor, dwMinor, dwPatch;
197
198     if (DwordDataRead(AFSREG_SVR_SW_VERSION_KEY,
199                       AFSREG_SVR_SW_VERSION_MAJOR_VALUE,
200                       &dwMajor) ||
201
202         DwordDataRead(AFSREG_SVR_SW_VERSION_KEY,
203                       AFSREG_SVR_SW_VERSION_MINOR_VALUE,
204                       &dwMinor) ||
205
206         DwordDataRead(AFSREG_SVR_SW_VERSION_KEY,
207                       AFSREG_SVR_SW_VERSION_PATCH_VALUE,
208                       &dwPatch)) {
209         /* a read failed */
210         return -1;
211     } else {
212         /* return values */
213         *major = dwMajor;
214         *minor = dwMinor;
215         *patch = dwPatch;
216         return 0;
217     }
218 }
219
220
221 /*
222  * afssw_GetClientVersion() -- Get version number of installed client.
223  *
224  * RETURN CODES: 0 success, -1 failed (errno set)
225  */
226 int
227 afssw_GetClientVersion(unsigned *major,  /* major version number */
228                        unsigned *minor,  /* minor version number */
229                        unsigned *patch)  /* patch level */
230 {
231     DWORD dwMajor, dwMinor, dwPatch;
232
233     if (DwordDataRead(AFSREG_CLT_SW_VERSION_KEY,
234                       AFSREG_CLT_SW_VERSION_MAJOR_VALUE,
235                       &dwMajor) ||
236
237         DwordDataRead(AFSREG_CLT_SW_VERSION_KEY,
238                       AFSREG_CLT_SW_VERSION_MINOR_VALUE,
239                       &dwMinor) ||
240
241         DwordDataRead(AFSREG_CLT_SW_VERSION_KEY,
242                       AFSREG_CLT_SW_VERSION_PATCH_VALUE,
243                       &dwPatch)) {
244         /* a read failed */
245         return -1;
246     } else {
247         /* return values */
248         *major = dwMajor;
249         *minor = dwMinor;
250         *patch = dwPatch;
251         return 0;
252     }
253 }
254
255
256
257
258 /* ----------------------- local functions ------------------------- */
259
260 /*
261  * StringDataRead() -- read registry data of type REG_SZ and return in
262  *     allocated buffer.
263  *
264  * RETURN CODES: 0 success, -1 failed (errno set)
265  */
266 static int
267 StringDataRead(const char *keyName, const char *valueName, char **bufPP)
268 {
269     long status;
270     HKEY key;
271
272     if (bufPP == NULL) {
273         errno = EINVAL;
274         return -1;
275     }
276
277     status = RegOpenKeyAlt(AFSREG_NULL_KEY, keyName, KEY_READ, 0, &key, NULL);
278
279     if (status == ERROR_SUCCESS) {
280         DWORD dataType;
281         char *dataBuf = NULL;
282
283         status = RegQueryValueAlt(key, valueName, &dataType, &dataBuf, NULL);
284
285         if (status == ERROR_SUCCESS) {
286             if (dataType == REG_SZ) {
287                 *bufPP = dataBuf;
288             } else {
289                 /* invalid data type */
290                 free(dataBuf);
291                 status = ERROR_INVALID_DATA;
292             }
293         }
294         (void)RegCloseKey(key);
295     }
296
297     if (status) {
298         errno = nterr_nt2unix(status, EIO);
299         return -1;
300     }
301     return 0;
302 }
303
304
305 /*
306  * StringDataWrite() -- write registry data of type REG_SZ.
307  * 
308  * RETURN CODES: 0 success, -1 failed (errno set)
309  */
310 static int
311 StringDataWrite(const char *keyName, const char *valueName, const char *data)
312 {
313     long status;
314     HKEY key;
315
316     if (data == NULL) {
317         errno = EINVAL;
318         return -1;
319     }
320
321     status = RegOpenKeyAlt(AFSREG_NULL_KEY,
322                            keyName, KEY_WRITE, 1 /* create */, &key, NULL);
323
324     if (status == ERROR_SUCCESS) {
325         status = RegSetValueEx(key,
326                                valueName,
327                                0, REG_SZ, data, (DWORD)strlen(data) + 1);
328
329         (void)RegCloseKey(key);
330     }
331
332     if (status) {
333         errno = nterr_nt2unix(status, EIO);
334         return -1;
335     }
336     return 0;
337 }
338
339
340 /*
341  * DwordDataRead() -- read registry data of type REG_DWORD.
342  *
343  * RETURN CODES: 0 success, -1 failed (errno set)
344  */
345 static int
346 DwordDataRead(const char *keyName, const char *valueName, DWORD *data)
347 {
348     long status;
349     HKEY key;
350
351     status = RegOpenKeyAlt(AFSREG_NULL_KEY, keyName, KEY_READ, 0, &key, NULL);
352
353     if (status == ERROR_SUCCESS) {
354         DWORD dataType;
355         DWORD dataBuf;
356         DWORD dataSize = sizeof(DWORD);
357
358         status = RegQueryValueEx(key, valueName,
359                                  NULL, &dataType, (void *)&dataBuf, &dataSize);
360
361         if (status == ERROR_SUCCESS) {
362             if (dataType == REG_DWORD) {
363                 *data = dataBuf;
364             } else {
365                 /* invalid data type */
366                 status = ERROR_INVALID_DATA;
367             }
368         }
369         (void)RegCloseKey(key);
370     }
371
372     if (status) {
373         errno = nterr_nt2unix(status, EIO);
374         return -1;
375     }
376     return 0;
377 }