Remove the RCSID macro
[openafs.git] / src / util / hostparse.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 /*
11  * ALL RIGHTS RESERVED
12  */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16
17
18 #ifdef UKERNEL
19 #include "afs/sysincludes.h"
20 #include "afs/afsutil.h"
21 #include <netdb.h>
22 #else /* UKERNEL */
23 #include <stdio.h>
24 #include <sys/types.h>
25 #include <stdlib.h>
26 #ifdef AFS_NT40_ENV
27 #include <winsock2.h>
28 #include <direct.h>
29 #else
30 #include <netinet/in.h>
31 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34 #include <ctype.h>
35 #endif
36 #include <string.h>
37 #include <errno.h>
38 #include "afsutil.h"
39 #endif /* UKERNEL */
40
41
42 /* also parse a.b.c.d addresses */
43 struct hostent *
44 hostutil_GetHostByName(register char *ahost)
45 {
46     register int tc;
47     static struct hostent thostent;
48     static char *addrp[2];
49     static char addr[4];
50     register char *ptr = ahost;
51     afs_uint32 tval, numeric = 0;
52     int dots = 0;
53
54     tc = *ahost;                /* look at the first char */
55     if (tc >= '0' && tc <= '9') {
56         numeric = 1;
57         while ((tc = *ptr++)) {
58             if (tc == '.') {
59                 if (dots >= 3) {
60                     numeric = 0;
61                     break;
62                 }
63                 dots++;
64             } else if (tc > '9' || tc < '0') {
65                 numeric = 0;
66                 break;
67             }
68         }
69     }
70     if (numeric) {
71         tc = *ahost;            /* look at the first char */
72         /* decimal address, return fake hostent with only hostaddr field good */
73         tval = 0;
74         dots = 0;
75         memset(addr, 0, sizeof(addr));
76         while ((tc = *ahost++)) {
77             if (tc == '.') {
78                 if (dots >= 3)
79                     return NULL;        /* too many dots */
80                 addr[dots++] = tval;
81                 tval = 0;
82             } else if (tc > '9' || tc < '0')
83                 return NULL;
84             else {
85                 tval *= 10;
86                 tval += tc - '0';
87             }
88         }
89         addr[dots] = tval;
90 #ifdef h_addr
91         /* 4.3 system */
92         addrp[0] = addr;
93         addrp[1] = NULL;
94         thostent.h_addr_list = &addrp[0];
95 #else /* h_addr */
96         /* 4.2 and older systems */
97         thostent.h_addr = addr;
98 #endif /* h_addr */
99         return &thostent;
100     } else {
101 #ifdef AFS_NT40_ENV
102         if (afs_winsockInit() < 0)
103             return NULL;
104 #endif
105         return gethostbyname(ahost);
106     }
107 }
108
109 /* Translate an internet address into a nice printable string. The
110  * variable addr is in network byte order.
111  */
112 char *
113 hostutil_GetNameByINet(afs_uint32 addr)
114 {
115     struct hostent *th;
116     static char tbuffer[256];
117
118 #ifdef AFS_NT40_ENV
119     if (afs_winsockInit() < 0)
120         return NULL;
121 #endif
122     th = gethostbyaddr((void *)&addr, sizeof(addr), AF_INET);
123     if (th) {
124         strcpy(tbuffer, th->h_name);
125     } else {
126         addr = ntohl(addr);
127         sprintf(tbuffer, "%d.%d.%d.%d", (int)((addr >> 24) & 0xff),
128                 (int)((addr >> 16) & 0xff), (int)((addr >> 8) & 0xff),
129                 (int)(addr & 0xff));
130     }
131
132     return tbuffer;
133 }
134
135 /* the parameter is a pointer to a buffer containing a string of 
136 ** bytes of the form 
137 ** w.x.y.z      # machineName
138 ** returns the network interface in network byte order 
139 */
140 afs_uint32
141 extractAddr(char *line, int maxSize)
142 {
143     char byte1[32], byte2[32], byte3[32], byte4[32];
144     int i = 0;
145     char *endPtr;
146     afs_uint32 val1, val2, val3, val4;
147     afs_uint32 val = 0;
148
149     /* skip empty spaces */
150     while (isspace(*line) && maxSize) {
151         line++;
152         maxSize--;
153     }
154
155     /* skip empty lines */
156     if (!maxSize || !*line)
157         return AFS_IPINVALIDIGNORE;
158
159     while ((*line != '.') && maxSize) { /* extract first byte */
160         if (!isdigit(*line))
161             return AFS_IPINVALID;
162         if (i > 31)
163             return AFS_IPINVALID;       /* no space */
164         byte1[i++] = *line++;
165         maxSize--;
166     }
167     if (!maxSize)
168         return AFS_IPINVALID;
169     byte1[i] = 0;
170
171     i = 0, line++;
172     while ((*line != '.') && maxSize) { /* extract second byte */
173         if (!isdigit(*line))
174             return AFS_IPINVALID;
175         if (i > 31)
176             return AFS_IPINVALID;       /* no space */
177         byte2[i++] = *line++;
178         maxSize--;
179     }
180     if (!maxSize)
181         return AFS_IPINVALID;
182     byte2[i] = 0;
183
184     i = 0, line++;
185     while ((*line != '.') && maxSize) {
186         if (!isdigit(*line))
187             return AFS_IPINVALID;
188         if (i > 31)
189             return AFS_IPINVALID;       /* no space */
190         byte3[i++] = *line++;
191         maxSize--;
192     }
193     if (!maxSize)
194         return AFS_IPINVALID;
195     byte3[i] = 0;
196
197     i = 0, line++;
198     while (*line && !isspace(*line) && maxSize) {
199         if (!isdigit(*line))
200             return AFS_IPINVALID;
201         if (i > 31)
202             return AFS_IPINVALID;       /* no space */
203         byte4[i++] = *line++;
204         maxSize--;
205     }
206     if (!maxSize)
207         return AFS_IPINVALID;
208     byte4[i] = 0;
209
210     errno = 0;
211     val1 = strtol(byte1, &endPtr, 10);
212     if ((val1 == 0) && (errno != 0 || byte1 == endPtr))
213         return AFS_IPINVALID;
214
215     errno = 0;
216     val2 = strtol(byte2, &endPtr, 10);
217     if ((val2 == 0) && (errno != 0 || byte2 == endPtr)) /* no conversion */
218         return AFS_IPINVALID;
219
220     errno = 0;
221     val3 = strtol(byte3, &endPtr, 10);
222     if ((val3 == 0) && (errno != 0 || byte3 == endPtr)) /* no conversion */
223         return AFS_IPINVALID;
224
225     errno = 0;
226     val4 = strtol(byte4, &endPtr, 10);
227     if ((val4 == 0) && (errno != 0 || byte4 == endPtr)) /* no conversion */
228         return AFS_IPINVALID;
229
230     val = (val1 << 24) | (val2 << 16) | (val3 << 8) | val4;
231     val = htonl(val);
232     return val;
233 }
234
235 /* 
236 ** converts a 4byte IP address into a static string (e.g. w.x.y.z) 
237 ** On Solaris, if we pass a 4 byte integer directly into inet_ntoa(), it
238 ** causes a memory fault. 
239 */
240 char *
241 afs_inet_ntoa(afs_uint32 addr)
242 {
243     struct in_addr temp;
244     temp.s_addr = addr;
245     return (char *)inet_ntoa(temp);
246 }
247
248 /* same as above, but to a non-static buffer, must be freed by called */
249 char *
250 afs_inet_ntoa_r(afs_uint32 addr, char *buf)
251 {
252     int temp;
253
254     temp = ntohl(addr);
255     sprintf(buf, "%d.%d.%d.%d", (temp >> 24) & 0xff, (temp >> 16) & 0xff,
256             (temp >> 8) & 0xff, (temp) & 0xff);
257     return buf;
258 }
259
260 /*
261  * gettmpdir() -- Returns pointer to global temporary directory string.
262  *     Always succeeds.  Never attempt to deallocate directory string.
263  */
264
265 char *
266 gettmpdir(void)
267 {
268     char *tmpdirp = NULL;
269
270 #ifdef AFS_NT40_ENV
271     static char *saveTmpDir = NULL;
272
273     if (saveTmpDir == NULL) {
274         /* initialize global temporary directory string */
275         char *dirp = (char *)malloc(MAX_PATH);
276         int freeDirp = 1;
277
278         if (dirp != NULL) {
279             DWORD pathLen = GetTempPath(MAX_PATH, dirp);
280
281             if (pathLen == 0 || pathLen > MAX_PATH) {
282                 /* can't get tmp path; get cur work dir */
283                 pathLen = GetCurrentDirectory(MAX_PATH, dirp);
284                 if (pathLen == 0 || pathLen > MAX_PATH) {
285                     free(dirp);
286                     dirp = NULL;
287                 }
288             }
289
290             if (dirp != NULL) {
291                 /* Have a valid dir path; check that actually exists. */
292                 DWORD fileAttr = GetFileAttributes(dirp);
293
294                 if ((fileAttr == 0xFFFFFFFF)
295                     || ((fileAttr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
296                     free(dirp);
297                     dirp = NULL;
298                 }
299             }
300         }
301         /* dirp != NULL */
302         if (dirp != NULL) {
303             FilepathNormalize(dirp);
304         } else {
305             /* most likely TMP or TEMP env vars specify a non-existent dir */
306             dirp = "/";
307             freeDirp = 0;
308         }
309
310         /* atomically initialize shared buffer pointer IF still null */
311
312 #if 0
313         if (InterlockedCompareExchange(&saveTmpDir, dirp, NULL) != NULL) {
314             /* shared buffer pointer already initialized by another thread */
315             if (freeDirp) {
316                 free(dirp);
317             }
318         }                       /* interlock xchng */
319 #endif
320
321         /* Above is what we really want to do, but Windows 95 does not have
322          * InterlockedCompareExchange().  So we just atomically swap
323          * the buffer pointer values but we do NOT deallocate the
324          * previously installed buffer, if any, in case it is in use.
325          */
326 #ifdef _WIN64
327         InterlockedExchange64((LONGLONG)(INT_PTR)&saveTmpDir, (LONGLONG) dirp);
328 #else
329         InterlockedExchange((LONG) & saveTmpDir, (LONG) dirp);
330 #endif
331
332     }
333     /* if (!saveTmpDir) */
334     tmpdirp = saveTmpDir;
335 #else
336     tmpdirp = "/tmp";
337 #endif /* AFS_NT40_ENV */
338
339     return tmpdirp;
340 }