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