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