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