]>
Commit | Line | Data |
---|---|---|
3bd189cb JR |
1 | /************************************************************************ |
2 | * IRC - Internet Relay Chat, common/support.c | |
3 | * Copyright (C) 1990, 1991 Armin Gruner | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 1, or (at your option) | |
8 | * any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | */ | |
19 | ||
20 | #ifndef lint | |
21 | static const volatile char rcsid[] = "@(#)$Id: support.c,v 1.46 2009/03/15 01:25:32 chopin Exp $"; | |
22 | #endif | |
23 | ||
24 | #include "os.h" | |
25 | #include "s_defines.h" | |
26 | #define SUPPORT_C | |
27 | #include "s_externs.h" | |
28 | #undef SUPPORT_C | |
29 | ||
30 | #ifdef INET6 | |
31 | char ipv6string[INET6_ADDRSTRLEN]; | |
32 | #endif | |
33 | ||
34 | unsigned char minus_one[]={ 255, 255, 255, 255, 255, 255, 255, 255, 255, | |
35 | 255, 255, 255, 255, 255, 255, 255, 0}; | |
36 | ||
37 | ||
38 | char *mystrdup(char *s) | |
39 | { | |
40 | /* Portable strdup(), contributed by mrg, thanks! -roy */ | |
41 | ||
42 | char *t; | |
43 | ||
44 | t = (char *) MyMalloc(strlen(s) + 1); | |
45 | if (t) | |
46 | return ((char *)strcpy(t, s)); | |
47 | return NULL; | |
48 | } | |
49 | ||
50 | #if defined(JAPANESE) && defined(HAVE_STRTOKEN) | |
51 | /* I doubt library strtoken knows about JIS encoding and commas. --Beeth */ | |
52 | #undef HAVE_STRTOKEN | |
53 | #undef strtoken | |
54 | #endif | |
55 | ||
56 | #if !defined(HAVE_STRTOKEN) | |
57 | /* | |
58 | ** strtoken.c -- walk through a string of tokens, using a set | |
59 | ** of separators | |
60 | ** argv 9/90 | |
61 | */ | |
62 | ||
63 | char *strtoken(char **save, char *str, char *fs) | |
64 | { | |
65 | char *pos = *save; /* keep last position across calls */ | |
66 | Reg char *tmp; | |
67 | ||
68 | if (str) | |
69 | pos = str; /* new string scan */ | |
70 | ||
71 | while (pos && *pos && index(fs, *pos) != NULL) | |
72 | pos++; /* skip leading separators */ | |
73 | ||
74 | if (!pos || !*pos) | |
75 | return (pos = *save = NULL); /* string contains only sep's */ | |
76 | ||
77 | tmp = pos; /* now, keep position of the token */ | |
78 | ||
79 | #ifdef JAPANESE | |
80 | /* We have to make special case for Japanese names when comma is | |
81 | ** a separator, as they may contain it between JIS marks. --Beeth. */ | |
82 | if (fs[0] == ',' && fs[1] == '\0') | |
83 | { | |
84 | int flag = 0; | |
85 | while (*pos) | |
86 | { | |
87 | if (!flag && *pos == ',') | |
88 | { | |
89 | break; | |
90 | } | |
91 | else if (pos[0] == '\033' | |
92 | && (pos[1] == '$' || pos[1] == '(') | |
93 | && pos[2] == 'B') | |
94 | { | |
95 | flag = (pos[1] == '$') ? 1 : 0; | |
96 | pos += 2; | |
97 | } | |
98 | pos++; | |
99 | } | |
100 | } | |
101 | else | |
102 | /* This came from original jp patch, but I believe it is wrong for | |
103 | ** cases when fs is two or more letters (index() allows it) and contains | |
104 | ** comma. Fortunately ircd does not use such, yet it is something | |
105 | ** to remember. --Beeth. */ | |
106 | #endif | |
107 | { | |
108 | while (*pos && index(fs, *pos) == NULL) | |
109 | pos++; /* skip content of the token */ | |
110 | } | |
111 | ||
112 | if (*pos) | |
113 | *pos++ = '\0'; /* remove first sep after the token */ | |
114 | else | |
115 | pos = NULL; /* end of string */ | |
116 | ||
117 | *save = pos; | |
118 | return(tmp); | |
119 | } | |
120 | #endif /* HAVE_STRTOKEN */ | |
121 | ||
122 | #if !defined(HAVE_STRTOK) | |
123 | /* | |
124 | ** NOT encouraged to use! | |
125 | */ | |
126 | ||
127 | char *strtok(char *str, char *fs) | |
128 | { | |
129 | static char *pos; | |
130 | ||
131 | return strtoken(&pos, str, fs); | |
132 | } | |
133 | ||
134 | #endif /* HAVE_STRTOK */ | |
135 | ||
136 | #if !defined(HAVE_STRERROR) | |
137 | /* | |
138 | ** strerror - return an appropriate system error string to a given errno | |
139 | ** | |
140 | ** argv 11/90 | |
141 | */ | |
142 | ||
143 | char *strerror(int err_no) | |
144 | { | |
145 | static char buff[40]; | |
146 | char *errp; | |
147 | ||
148 | errp = (err_no > sys_nerr ? (char *)NULL : sys_errlist[err_no]); | |
149 | ||
150 | if (errp == (char *)NULL) | |
151 | { | |
152 | errp = buff; | |
153 | sprintf(errp, "Unknown Error %d", err_no); | |
154 | } | |
155 | return errp; | |
156 | } | |
157 | ||
158 | #endif /* HAVE_STRERROR */ | |
159 | ||
160 | /** | |
161 | ** myctime() | |
162 | ** This is like standard ctime()-function, but it zaps away | |
163 | ** the newline from the end of that string. Also, it takes | |
164 | ** the time value as parameter, instead of pointer to it. | |
165 | ** Note that it is necessary to copy the string to alternate | |
166 | ** buffer (who knows how ctime() implements it, maybe it statically | |
167 | ** has newline there and never 'refreshes' it -- zapping that | |
168 | ** might break things in other places...) | |
169 | ** | |
170 | **/ | |
171 | ||
172 | char *myctime(time_t value) | |
173 | { | |
174 | static char buf[28]; | |
175 | Reg char *p; | |
176 | ||
177 | (void)strcpy(buf, ctime(&value)); | |
178 | if ((p = (char *)index(buf, '\n')) != NULL) | |
179 | *p = '\0'; | |
180 | ||
181 | return buf; | |
182 | } | |
183 | ||
184 | /* | |
185 | ** mybasename() | |
186 | ** removes path from a filename | |
187 | */ | |
188 | char *mybasename(char *path) | |
189 | { | |
190 | char *lastslash; | |
191 | ||
192 | if ((lastslash = rindex(path, '/'))) | |
193 | { | |
194 | return lastslash + 1; | |
195 | } | |
196 | return path; | |
197 | } | |
198 | ||
199 | #ifdef INET6 | |
200 | /* | |
201 | * inetntop: return the : notation of a given IPv6 internet number. | |
202 | * or the dotted-decimal notation for IPv4 | |
203 | * make sure the compressed representation (rfc 1884) isn't used. | |
204 | */ | |
205 | char *inetntop(int af, const void *in, char *out, size_t the_size) | |
206 | { | |
207 | static char local_ipv6string[INET6_ADDRSTRLEN]; | |
208 | ||
209 | if (the_size > sizeof(local_ipv6string)) | |
210 | { | |
211 | the_size = sizeof(local_ipv6string); | |
212 | } | |
213 | ||
214 | if (!inet_ntop(af, in, local_ipv6string, the_size)) | |
215 | { | |
216 | /* good that every function calling this one | |
217 | * checks the return value ... NOT */ | |
218 | return NULL; | |
219 | } | |
220 | /* quick and dirty hack to give ipv4 just ipv4 instead of | |
221 | * ::ffff:ipv4 - Q */ | |
222 | if (af == AF_INET6 && IN6_IS_ADDR_V4MAPPED((const struct in6_addr *)in)) | |
223 | { | |
224 | char *p; | |
225 | ||
226 | if (!(p = strstr(local_ipv6string, ":ffff:")) && | |
227 | !(p = strstr(local_ipv6string, ":FFFF:"))) | |
228 | { | |
229 | return NULL; /* crash and burn */ | |
230 | } | |
231 | strcpy(out, p + 6); | |
232 | return out; | |
233 | } | |
234 | if (strstr(local_ipv6string, "::")) | |
235 | { | |
236 | char cnt = 0, *cp = local_ipv6string, *op = out; | |
237 | ||
238 | while (*cp) | |
239 | { | |
240 | if (*cp == ':') | |
241 | cnt += 1; | |
242 | if (*cp++ == '.') | |
243 | { | |
244 | cnt += 1; | |
245 | break; | |
246 | } | |
247 | } | |
248 | cp = local_ipv6string; | |
249 | while (*cp) | |
250 | { | |
251 | *op++ = *cp++; | |
252 | if (*(cp-1) == ':' && *cp == ':') | |
253 | { | |
254 | if ((cp-1) == local_ipv6string) | |
255 | { | |
256 | op--; | |
257 | *op++ = '0'; | |
258 | *op++ = ':'; | |
259 | } | |
260 | ||
261 | *op++ = '0'; | |
262 | while (cnt++ < 7) | |
263 | { | |
264 | *op++ = ':'; | |
265 | *op++ = '0'; | |
266 | } | |
267 | } | |
268 | } | |
269 | if (*(op-1)==':') *op++ = '0'; | |
270 | *op = '\0'; | |
271 | #ifndef CLIENT_COMPILE | |
272 | Debug((DEBUG_DNS,"Expanding `%s' -> `%s'", local_ipv6string, | |
273 | out)); | |
274 | #endif | |
275 | } | |
276 | else | |
277 | bcopy(local_ipv6string, out, the_size); | |
278 | ||
279 | return out; | |
280 | } | |
281 | ||
282 | /* inetpton(af, src, dst) | |
283 | ** | |
284 | ** This is a wrapper for inet_pton(), so we can use ipv4 addresses with an | |
285 | ** af of AF_INET6, and that it gets converted to ipv4 mapped ipv6. | |
286 | */ | |
287 | int inetpton(int af, const char *src, void *dst) | |
288 | { | |
289 | int i; | |
290 | ||
291 | /* an empty string should listen to all */ | |
292 | if (af == AF_INET6 && *src && !strchr(src, ':')) | |
293 | { | |
294 | i = inet_pton(AF_INET, src, dst); | |
295 | ||
296 | /* ugly hack */ | |
297 | memcpy((char *)dst + 12, dst, 4); | |
298 | memset(dst, 0, 10); | |
299 | memset((char *)dst + 10, 0xff, 2); | |
300 | return i; | |
301 | } | |
302 | return inet_pton(af, src, dst); | |
303 | } | |
304 | #endif | |
305 | ||
306 | #if !defined(HAVE_INET_NTOA) | |
307 | /* | |
308 | ** inetntoa -- changed name to remove collision possibility and | |
309 | ** so behaviour is gaurunteed to take a pointer arg. | |
310 | ** -avalon 23/11/92 | |
311 | ** inet_ntoa -- returned the dotted notation of a given | |
312 | ** internet number (some ULTRIX don't have this) | |
313 | ** argv 11/90). | |
314 | ** inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon | |
315 | */ | |
316 | ||
317 | char *inetntoa(char *in) | |
318 | { | |
319 | static char buf[16]; | |
320 | Reg u_char *s = (u_char *)in; | |
321 | Reg int a,b,c,d; | |
322 | ||
323 | a = (int)*s++; | |
324 | b = (int)*s++; | |
325 | c = (int)*s++; | |
326 | d = (int)*s; | |
327 | (void)sprintf(buf, "%d.%d.%d.%d", a,b,c,d ); | |
328 | ||
329 | return buf; | |
330 | } | |
331 | #endif | |
332 | ||
333 | #if !defined(HAVE_INET_NETOF) | |
334 | /* | |
335 | ** inet_netof -- return the net portion of an internet number | |
336 | ** argv 11/90 | |
337 | */ | |
338 | int inetnetof(struct in_addr in) | |
339 | { | |
340 | register u_long i = ntohl(in.s_addr); | |
341 | ||
342 | if (IN_CLASSA(i)) | |
343 | return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT); | |
344 | else if (IN_CLASSB(i)) | |
345 | return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT); | |
346 | else | |
347 | return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); | |
348 | } | |
349 | #endif | |
350 | ||
351 | #if !defined(HAVE_INET_ADDR) | |
352 | # ifndef INADDR_NONE | |
353 | # define INADDR_NONE 0xffffffff | |
354 | # endif | |
355 | /* | |
356 | * Ascii internet address interpretation routine. | |
357 | * The value returned is in network order. | |
358 | */ | |
359 | u_long inetaddr(const char *cp) | |
360 | { | |
361 | struct in_addr val; | |
362 | ||
363 | if (inetaton(cp, &val)) | |
364 | return (val.s_addr); | |
365 | return (INADDR_NONE); | |
366 | } | |
367 | #endif | |
368 | ||
369 | #if !defined(HAVE_INET_ATON) | |
370 | /* | |
371 | * Check whether "cp" is a valid ascii representation | |
372 | * of an Internet address and convert to a binary address. | |
373 | * Returns 1 if the address is valid, 0 if not. | |
374 | * This replaces inet_addr, the return value from which | |
375 | * cannot distinguish between failure and a local broadcast address. | |
376 | */ | |
377 | int inetaton(const char *cp, struct in_addr *addr) | |
378 | { | |
379 | register u_long val; | |
380 | register int base, n; | |
381 | register char c; | |
382 | u_int parts[4]; | |
383 | register u_int *pp = parts; | |
384 | ||
385 | c = *cp; | |
386 | for (;;) { | |
387 | /* | |
388 | * Collect number up to ``.''. | |
389 | * Values are specified as for C: | |
390 | * 0x=hex, 0=octal, isdigit=decimal. | |
391 | */ | |
392 | if (!isdigit(c)) | |
393 | return (0); | |
394 | val = 0; base = 10; | |
395 | if (c == '0') { | |
396 | c = *++cp; | |
397 | if (c == 'x' || c == 'X') | |
398 | base = 16, c = *++cp; | |
399 | else | |
400 | base = 8; | |
401 | } | |
402 | for (;;) { | |
403 | if (isascii(c) && isdigit(c)) { | |
404 | val = (val * base) + (c - '0'); | |
405 | c = *++cp; | |
406 | } else if (base == 16 && isascii(c) && isxdigit(c)) { | |
407 | val = (val << 4) | | |
408 | (c + 10 - (islower(c) ? 'a' : 'A')); | |
409 | c = *++cp; | |
410 | } else | |
411 | break; | |
412 | } | |
413 | if (c == '.') { | |
414 | /* | |
415 | * Internet format: | |
416 | * a.b.c.d | |
417 | * a.b.c (with c treated as 16 bits) | |
418 | * a.b (with b treated as 24 bits) | |
419 | */ | |
420 | if (pp >= parts + 3) | |
421 | return (0); | |
422 | *pp++ = val; | |
423 | c = *++cp; | |
424 | } else | |
425 | break; | |
426 | } | |
427 | /* | |
428 | * Check for trailing characters. | |
429 | */ | |
430 | if (c != '\0' && (!isascii(c) || !isspace(c))) | |
431 | return (0); | |
432 | /* | |
433 | * Concoct the address according to | |
434 | * the number of parts specified. | |
435 | */ | |
436 | n = pp - parts + 1; | |
437 | switch (n) { | |
438 | ||
439 | case 0: | |
440 | return (0); /* initial nondigit */ | |
441 | ||
442 | case 1: /* a -- 32 bits */ | |
443 | break; | |
444 | ||
445 | case 2: /* a.b -- 8.24 bits */ | |
446 | if (val > 0xffffff) | |
447 | return (0); | |
448 | val |= parts[0] << 24; | |
449 | break; | |
450 | ||
451 | case 3: /* a.b.c -- 8.8.16 bits */ | |
452 | if (val > 0xffff) | |
453 | return (0); | |
454 | val |= (parts[0] << 24) | (parts[1] << 16); | |
455 | break; | |
456 | ||
457 | case 4: /* a.b.c.d -- 8.8.8.8 bits */ | |
458 | if (val > 0xff) | |
459 | return (0); | |
460 | val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); | |
461 | break; | |
462 | } | |
463 | if (addr) | |
464 | addr->s_addr = htonl(val); | |
465 | return (1); | |
466 | } | |
467 | #endif | |
468 | ||
469 | #if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) | |
470 | void dumpcore(char *msg, ...) | |
471 | { | |
472 | static time_t lastd = 0; | |
473 | static int dumps = 0; | |
474 | char corename[12]; | |
475 | time_t now; | |
476 | int p; | |
477 | va_list va; | |
478 | char s[BUFSIZE]; | |
479 | ||
480 | now = time(NULL); | |
481 | ||
482 | if (!lastd) | |
483 | lastd = now; | |
484 | else if (now - lastd < 60 && dumps > 2) | |
485 | (void)s_die(0); | |
486 | if (now - lastd > 60) | |
487 | { | |
488 | lastd = now; | |
489 | dumps = 1; | |
490 | } | |
491 | else | |
492 | dumps++; | |
493 | p = getpid(); | |
494 | if (fork()>0) { | |
495 | kill(p, 3); | |
496 | kill(p, 9); | |
497 | } | |
498 | write_pidfile(); | |
499 | sprintf(corename, "core.%d", p); | |
500 | (void)rename("core", corename); | |
501 | va_start(va, msg); | |
502 | vsprintf(s, msg, va); | |
503 | va_end(va); | |
504 | Debug((DEBUG_FATAL, s)); | |
505 | sendto_flag(SCH_ERROR, "Dumped core : core.%d", p); | |
506 | Debug((DEBUG_FATAL, s)); | |
507 | sendto_flag(SCH_ERROR, s); | |
508 | (void)s_die(0); | |
509 | } | |
510 | #endif | |
511 | ||
512 | #if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) && defined(DO_DEBUG_MALLOC) | |
513 | ||
514 | static char *marray[100000]; | |
515 | static int mindex = 0; | |
516 | ||
517 | #define SZ_EX (sizeof(char *) + sizeof(size_t) + 4) | |
518 | #define SZ_CHST (sizeof(char *) + sizeof(size_t)) | |
519 | #define SZ_CH (sizeof(char *)) | |
520 | #define SZ_ST (sizeof(size_t)) | |
521 | ||
522 | char *MyMalloc(size_t x) | |
523 | { | |
524 | register int i; | |
525 | register char **s; | |
526 | char *ret; | |
527 | ||
528 | ret = (char *)malloc(x + (size_t)SZ_EX); | |
529 | ||
530 | if (!ret) | |
531 | { | |
532 | # ifndef CLIENT_COMPILE | |
533 | outofmemory(); | |
534 | # else | |
535 | perror("malloc"); | |
536 | exit(-1); | |
537 | # endif | |
538 | } | |
539 | bzero(ret, (int)x + SZ_EX); | |
540 | bcopy((char *)&ret, ret, SZ_CH); | |
541 | bcopy((char *)&x, ret + SZ_CH, SZ_ST); | |
542 | bcopy("VAVA", ret + SZ_CHST + (int)x, 4); | |
543 | Debug((DEBUG_MALLOC, "MyMalloc(%ld) = %#x", x, ret + SZ_CHST)); | |
544 | for(i = 0, s = marray; *s && i < mindex; i++, s++) | |
545 | ; | |
546 | if (i < 100000) | |
547 | { | |
548 | *s = ret; | |
549 | if (i == mindex) | |
550 | mindex++; | |
551 | } | |
552 | return ret + SZ_CHST; | |
553 | } | |
554 | ||
555 | char *MyRealloc(char *x, size_t y) | |
556 | { | |
557 | register int l; | |
558 | register char **s; | |
559 | char *ret, *cp; | |
560 | size_t i; | |
561 | int k; | |
562 | ||
563 | if (x != NULL) | |
564 | { | |
565 | x -= SZ_CHST; | |
566 | bcopy(x, (char *)&cp, SZ_CH); | |
567 | bcopy(x + SZ_CH, (char *)&i, SZ_ST); | |
568 | bcopy(x + (int)i + SZ_CHST, (char *)&k, 4); | |
569 | if (bcmp((char *)&k, "VAVA", 4) || (x != cp)) | |
570 | dumpcore("MyRealloc %#x %d %d %#x %#x", x, y, i, cp, k); | |
571 | } | |
572 | ret = (char *)realloc(x, y + (size_t)SZ_EX); | |
573 | ||
574 | if (!ret) | |
575 | { | |
576 | # ifndef CLIENT_COMPILE | |
577 | outofmemory(); | |
578 | # else | |
579 | perror("realloc"); | |
580 | exit(-1); | |
581 | # endif | |
582 | } | |
583 | bcopy((char *)&ret, ret, SZ_CH); | |
584 | bcopy((char *)&y, ret + SZ_CH, SZ_ST); | |
585 | bcopy("VAVA", ret + SZ_CHST + (int)y, 4); | |
586 | Debug((DEBUG_NOTICE, "MyRealloc(%#x,%ld) = %#x", x, y, ret + SZ_CHST)); | |
587 | for(l = 0, s = marray; *s != x && l < mindex; l++, s++) | |
588 | ; | |
589 | if (l < mindex) | |
590 | *s = NULL; | |
591 | else if (l == mindex) | |
592 | Debug((DEBUG_MALLOC, "%#x !found", x)); | |
593 | for(l = 0, s = marray; *s && l < mindex; l++,s++) | |
594 | ; | |
595 | if (l < 100000) | |
596 | { | |
597 | *s = ret; | |
598 | if (l == mindex) | |
599 | mindex++; | |
600 | } | |
601 | return ret + SZ_CHST; | |
602 | } | |
603 | ||
604 | void MyFree(void *p) | |
605 | { | |
606 | size_t i; | |
607 | char *j, *x = p; | |
608 | u_char k[4]; | |
609 | register int l; | |
610 | register char **s; | |
611 | ||
612 | if (!x) | |
613 | return; | |
614 | x -= SZ_CHST; | |
615 | ||
616 | bcopy(x, (char *)&j, SZ_CH); | |
617 | bcopy(x + SZ_CH, (char *)&i, SZ_ST); | |
618 | bcopy(x + SZ_CHST + (int)i, (char *)k, 4); | |
619 | ||
620 | if (bcmp((char *)k, "VAVA", 4) || (j != x)) | |
621 | dumpcore("MyFree %#x %ld %#x %#x", x, i, j, | |
622 | (k[3]<<24) | (k[2]<<16) | (k[1]<<8) | k[0]); | |
623 | ||
624 | Debug((DEBUG_MALLOC, "MyFree(%#x)",x + SZ_CHST)); | |
625 | #undef free | |
626 | (void)free(x); | |
627 | #define free(x) MyFree(x) | |
628 | ||
629 | for (l = 0, s = marray; *s != x && l < mindex; l++, s++) | |
630 | ; | |
631 | if (l < mindex) | |
632 | *s = NULL; | |
633 | else if (l == mindex) | |
634 | Debug((DEBUG_MALLOC, "%#x !found", x)); | |
635 | } | |
636 | #else | |
637 | char *MyMalloc(size_t x) | |
638 | { | |
639 | char *ret = (char *)malloc(x); | |
640 | ||
641 | if (!ret) | |
642 | { | |
643 | # ifndef CLIENT_COMPILE | |
644 | outofmemory(); | |
645 | # else | |
646 | perror("malloc"); | |
647 | exit(-1); | |
648 | # endif | |
649 | } | |
650 | return ret; | |
651 | } | |
652 | ||
653 | char *MyRealloc(char *x, size_t y) | |
654 | { | |
655 | char *ret = (char *)realloc(x, y); | |
656 | ||
657 | if (!ret) | |
658 | { | |
659 | # ifndef CLIENT_COMPILE | |
660 | outofmemory(); | |
661 | # else | |
662 | perror("realloc"); | |
663 | exit(-1); | |
664 | # endif | |
665 | } | |
666 | return ret; | |
667 | } | |
668 | #endif | |
669 | ||
670 | ||
671 | /* | |
672 | ** read a string terminated by \r or \n in from a fd | |
673 | ** | |
674 | ** Created: Sat Dec 12 06:29:58 EST 1992 by avalon | |
675 | ** Returns: | |
676 | ** 0 - EOF | |
677 | ** -1 - error on read | |
678 | ** >0 - number of bytes returned (<=num) | |
679 | ** After opening a fd, it is necessary to init dgets() by calling it as | |
680 | ** dgets(x,y,0); | |
681 | ** to mark the buffer as being empty. | |
682 | */ | |
683 | int dgets(int fd, char *buf, int num) | |
684 | { | |
685 | static char dgbuf[8192]; | |
686 | static char *head = dgbuf, *tail = dgbuf; | |
687 | register char *s, *t; | |
688 | register int n, nr; | |
689 | ||
690 | /* | |
691 | ** Sanity checks. | |
692 | */ | |
693 | if (head == tail) | |
694 | *head = '\0'; | |
695 | if (!num) | |
696 | { | |
697 | head = tail = dgbuf; | |
698 | *head = '\0'; | |
699 | return 0; | |
700 | } | |
701 | if (num > sizeof(dgbuf) - 1) | |
702 | num = sizeof(dgbuf) - 1; | |
703 | dgetsagain: | |
704 | if (head > dgbuf) | |
705 | { | |
706 | for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--) | |
707 | *t++ = *s++; | |
708 | tail = t; | |
709 | head = dgbuf; | |
710 | } | |
711 | /* | |
712 | ** check input buffer for EOL and if present return string. | |
713 | */ | |
714 | if (head < tail && | |
715 | ((s = index(head, '\n')) || (s = index(head, '\r'))) && s < tail) | |
716 | { | |
717 | n = MIN(s - head + 1, num); /* at least 1 byte */ | |
718 | dgetsreturnbuf: | |
719 | bcopy(head, buf, n); | |
720 | head += n; | |
721 | if (head == tail) | |
722 | head = tail = dgbuf; | |
723 | return n; | |
724 | } | |
725 | ||
726 | if (tail - head >= num) /* dgets buf is big enough */ | |
727 | { | |
728 | n = num; | |
729 | goto dgetsreturnbuf; | |
730 | } | |
731 | ||
732 | n = sizeof(dgbuf) - (tail - dgbuf) - 1; | |
733 | nr = read(fd, tail, n); | |
734 | if (nr == -1) | |
735 | { | |
736 | head = tail = dgbuf; | |
737 | return -1; | |
738 | } | |
739 | if (!nr) | |
740 | { | |
741 | if (tail > head) | |
742 | { | |
743 | n = MIN(tail - head, num); | |
744 | goto dgetsreturnbuf; | |
745 | } | |
746 | head = tail = dgbuf; | |
747 | return 0; | |
748 | } | |
749 | tail += nr; | |
750 | *tail = '\0'; | |
751 | for (t = head; (s = index(t, '\n')); ) | |
752 | { | |
753 | if ((s > head) && (s > dgbuf)) | |
754 | { | |
755 | t = s-1; | |
756 | for (nr = 0; *t == '\\'; nr++) | |
757 | t--; | |
758 | if (nr & 1) | |
759 | { | |
760 | t = s+1; | |
761 | s--; | |
762 | nr = tail - t; | |
763 | while (nr--) | |
764 | *s++ = *t++; | |
765 | tail -= 2; | |
766 | *tail = '\0'; | |
767 | } | |
768 | else | |
769 | s++; | |
770 | } | |
771 | else | |
772 | s++; | |
773 | t = s; | |
774 | } | |
775 | *tail = '\0'; | |
776 | goto dgetsagain; | |
777 | } | |
778 | ||
779 | /* | |
780 | * Make 'readable' version string. | |
781 | */ | |
782 | char *make_version(void) | |
783 | { | |
784 | int ve, re, mi, dv, pl; | |
785 | char ver[15]; | |
786 | ||
787 | sscanf(PATCHLEVEL, "%2d%2d%2d%2d%2d", &ve, &re, &mi, &dv, &pl); | |
788 | /* version & revision */ | |
789 | sprintf(ver, "%d.%d", ve, (mi == 99) ? re + 1 : re); | |
790 | if (mi == 99) mi = -1; | |
791 | /* minor revision */ | |
792 | sprintf(ver + strlen(ver), ".%d", dv ? mi+1 : mi); | |
793 | if (dv) /* alpha/beta, note how visual patchlevel is raised above */ | |
794 | sprintf(ver + strlen(ver), "%c%d", DEVLEVEL, dv); | |
795 | if (pl) /* patchlevel */ | |
796 | sprintf(ver + strlen(ver), "p%d", pl); | |
797 | return mystrdup(ver); | |
798 | } | |
799 | ||
800 | #ifndef CLIENT_COMPILE | |
801 | /* Make RPL_ISUPPORT (005) numeric contents */ | |
802 | char **make_isupport(void) | |
803 | { | |
804 | char **tis; | |
805 | ||
806 | tis = (char **) MyMalloc(3 * sizeof(char *)); | |
807 | ||
808 | /* Warning: There must be up to 12 tokens in each string */ | |
809 | tis[0] = (char *) MyMalloc(BUFSIZE); | |
810 | sprintf(tis[0], | |
811 | "RFC2812 PREFIX=(ov)@+ CHANTYPES=#&!+ MODES=%d " | |
812 | "CHANLIMIT=#&!+:%d " | |
813 | "NICKLEN=%d TOPICLEN=%d KICKLEN=%d MAXLIST=beIR:%d " | |
814 | "CHANNELLEN=%d IDCHAN=!:%d CHANMODES=beIR,k,l,imnpstaqr", | |
815 | MAXMODEPARAMS, MAXCHANNELSPERUSER, | |
816 | LOCALNICKLEN, TOPICLEN, TOPICLEN, MAXBANS, CHANNELLEN, CHIDLEN); | |
817 | ||
818 | tis[1] = (char *) MyMalloc(BUFSIZE); | |
819 | sprintf(tis[1], "PENALTY FNC EXCEPTS=e INVEX=I CASEMAPPING=ascii"); | |
820 | if (networkname) | |
821 | { | |
822 | strcat(tis[1], " NETWORK="); | |
823 | strcat(tis[1], networkname); | |
824 | } | |
825 | ||
826 | tis[2] = NULL; | |
827 | ||
828 | return tis; | |
829 | } | |
830 | #endif | |
831 | ||
832 | #ifndef HAVE_TRUNCATE | |
833 | /* truncate: set a file to a specified length | |
834 | * I don't know of any UNIX that doesn't have truncate, but CYGWIN32 beta18 | |
835 | * doesn't have it. -krys | |
836 | * Replacement version from Dave Miller. | |
837 | */ | |
838 | int truncate(const char *path, off_t length) | |
839 | { | |
840 | int fd, res; | |
841 | fd = open(path, O_WRONLY); | |
842 | if (fd == -1) | |
843 | return -1; | |
844 | res = ftruncate(fd, length); | |
845 | close(fd); | |
846 | return res; | |
847 | } | |
848 | #endif /* HAVE_TRUNCATE */ | |
849 | ||
850 | #ifdef SOLARIS_2_3 | |
851 | /* | |
852 | * On Solaris 2.3 (SunOS 5.3) systems, gethostbyname() has a bug, it always | |
853 | * returns null in h->aliases. Workaround: use the undocumented | |
854 | * _switch_gethostbyname_r(...). | |
855 | */ | |
856 | #define HBUFSIZE 4096 | |
857 | ||
858 | struct hostent *solaris_gethostbyname(const char *name) | |
859 | { | |
860 | static struct hostent hp; | |
861 | static char buf[HBUFSIZE]; | |
862 | ||
863 | return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); | |
864 | } | |
865 | #endif /* SOLARIS_2_3 */ | |
866 | ||
867 | #if defined(HAVE_MEMCMP) && defined(MEMCMP_BROKEN) | |
868 | /* | |
869 | * Some OS may have a memcmp that is not 8-bit clean. | |
870 | * | |
871 | * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc. | |
872 | * Contributed by Torbjorn Granlund (tege@sics.se). | |
873 | * | |
874 | * NOTE: The canonical source of this part of the file is maintained with the | |
875 | * GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. | |
876 | */ | |
877 | ||
878 | /* Type to use for aligned memory operations. | |
879 | This should normally be the biggest type supported by a single load | |
880 | and store. Must be an unsigned type. */ | |
881 | #define op_t unsigned long int | |
882 | #define OPSIZ (sizeof(op_t)) | |
883 | ||
884 | /* Threshold value for when to enter the unrolled loops. */ | |
885 | #define OP_T_THRES 16 | |
886 | ||
887 | /* Type to use for unaligned operations. */ | |
888 | typedef unsigned char byte; | |
889 | ||
890 | #if !defined(WORDS_BIGENDIAN) | |
891 | #define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2))) | |
892 | #else | |
893 | #define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2))) | |
894 | #endif | |
895 | ||
896 | #if defined(WORDS_BIGENDIAN) | |
897 | #define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1) | |
898 | #else | |
899 | #define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b)) | |
900 | #endif | |
901 | ||
902 | /* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */ | |
903 | ||
904 | /* The strategy of this memcmp is: | |
905 | ||
906 | 1. Compare bytes until one of the block pointers is aligned. | |
907 | ||
908 | 2. Compare using memcmp_common_alignment or | |
909 | memcmp_not_common_alignment, regarding the alignment of the other | |
910 | block after the initial byte operations. The maximum number of | |
911 | full words (of type op_t) are compared in this way. | |
912 | ||
913 | 3. Compare the few remaining bytes. */ | |
914 | ||
915 | #if !defined(WORDS_BIGENDIAN) | |
916 | /* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine. | |
917 | A and B are known to be different. | |
918 | This is needed only on little-endian machines. */ | |
919 | #ifdef __GNUC__ | |
920 | __inline | |
921 | #endif | |
922 | static int memcmp_bytes(op_t a, op_t b) | |
923 | { | |
924 | long int srcp1 = (long int) &a; | |
925 | long int srcp2 = (long int) &b; | |
926 | op_t a0, b0; | |
927 | ||
928 | do | |
929 | { | |
930 | a0 = ((byte *) srcp1)[0]; | |
931 | b0 = ((byte *) srcp2)[0]; | |
932 | srcp1 += 1; | |
933 | srcp2 += 1; | |
934 | } | |
935 | while (a0 == b0); | |
936 | return a0 - b0; | |
937 | } | |
938 | #endif | |
939 | ||
940 | /* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t' | |
941 | objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for | |
942 | memory operations on `op_t's. */ | |
943 | #ifdef __GNUC__ | |
944 | __inline | |
945 | #endif | |
946 | static int memcmp_common_alignment(long int srcp1, long int srcp2, | |
947 | size_t len) | |
948 | { | |
949 | op_t a0, a1; | |
950 | op_t b0, b1; | |
951 | ||
952 | switch (len % 4) | |
953 | { | |
954 | case 2: | |
955 | a0 = ((op_t *) srcp1)[0]; | |
956 | b0 = ((op_t *) srcp2)[0]; | |
957 | srcp1 -= 2 * OPSIZ; | |
958 | srcp2 -= 2 * OPSIZ; | |
959 | len += 2; | |
960 | goto do1; | |
961 | case 3: | |
962 | a1 = ((op_t *) srcp1)[0]; | |
963 | b1 = ((op_t *) srcp2)[0]; | |
964 | srcp1 -= OPSIZ; | |
965 | srcp2 -= OPSIZ; | |
966 | len += 1; | |
967 | goto do2; | |
968 | case 0: | |
969 | if (OP_T_THRES <= 3 * OPSIZ && len == 0) | |
970 | return 0; | |
971 | a0 = ((op_t *) srcp1)[0]; | |
972 | b0 = ((op_t *) srcp2)[0]; | |
973 | goto do3; | |
974 | case 1: | |
975 | a1 = ((op_t *) srcp1)[0]; | |
976 | b1 = ((op_t *) srcp2)[0]; | |
977 | srcp1 += OPSIZ; | |
978 | srcp2 += OPSIZ; | |
979 | len -= 1; | |
980 | if (OP_T_THRES <= 3 * OPSIZ && len == 0) | |
981 | goto do0; | |
982 | /* Fall through. */ | |
983 | } | |
984 | ||
985 | do | |
986 | { | |
987 | a0 = ((op_t *) srcp1)[0]; | |
988 | b0 = ((op_t *) srcp2)[0]; | |
989 | if (a1 != b1) | |
990 | return CMP_LT_OR_GT (a1, b1); | |
991 | ||
992 | do3: | |
993 | a1 = ((op_t *) srcp1)[1]; | |
994 | b1 = ((op_t *) srcp2)[1]; | |
995 | if (a0 != b0) | |
996 | return CMP_LT_OR_GT (a0, b0); | |
997 | ||
998 | do2: | |
999 | a0 = ((op_t *) srcp1)[2]; | |
1000 | b0 = ((op_t *) srcp2)[2]; | |
1001 | if (a1 != b1) | |
1002 | return CMP_LT_OR_GT (a1, b1); | |
1003 | ||
1004 | do1: | |
1005 | a1 = ((op_t *) srcp1)[3]; | |
1006 | b1 = ((op_t *) srcp2)[3]; | |
1007 | if (a0 != b0) | |
1008 | return CMP_LT_OR_GT (a0, b0); | |
1009 | ||
1010 | srcp1 += 4 * OPSIZ; | |
1011 | srcp2 += 4 * OPSIZ; | |
1012 | len -= 4; | |
1013 | } | |
1014 | while (len != 0); | |
1015 | ||
1016 | /* This is the right position for do0. Please don't move | |
1017 | it into the loop. */ | |
1018 | do0: | |
1019 | if (a1 != b1) | |
1020 | return CMP_LT_OR_GT (a1, b1); | |
1021 | return 0; | |
1022 | } | |
1023 | ||
1024 | /* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN | |
1025 | `op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory | |
1026 | operations on `op_t', but SRCP1 *should be unaligned*. */ | |
1027 | #ifdef __GNUC__ | |
1028 | __inline | |
1029 | #endif | |
1030 | static int memcmp_not_common_alignment(long int srcp1, long int srcp2, | |
1031 | size_t len) | |
1032 | { | |
1033 | op_t a0, a1, a2, a3; | |
1034 | op_t b0, b1, b2, b3; | |
1035 | op_t x; | |
1036 | int shl, shr; | |
1037 | ||
1038 | /* Calculate how to shift a word read at the memory operation | |
1039 | aligned srcp1 to make it aligned for comparison. */ | |
1040 | ||
1041 | shl = 8 * (srcp1 % OPSIZ); | |
1042 | shr = 8 * OPSIZ - shl; | |
1043 | ||
1044 | /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t' | |
1045 | it points in the middle of. */ | |
1046 | srcp1 &= -OPSIZ; | |
1047 | ||
1048 | switch (len % 4) | |
1049 | { | |
1050 | case 2: | |
1051 | a1 = ((op_t *) srcp1)[0]; | |
1052 | a2 = ((op_t *) srcp1)[1]; | |
1053 | b2 = ((op_t *) srcp2)[0]; | |
1054 | srcp1 -= 1 * OPSIZ; | |
1055 | srcp2 -= 2 * OPSIZ; | |
1056 | len += 2; | |
1057 | goto do1; | |
1058 | case 3: | |
1059 | a0 = ((op_t *) srcp1)[0]; | |
1060 | a1 = ((op_t *) srcp1)[1]; | |
1061 | b1 = ((op_t *) srcp2)[0]; | |
1062 | srcp2 -= 1 * OPSIZ; | |
1063 | len += 1; | |
1064 | goto do2; | |
1065 | case 0: | |
1066 | if (OP_T_THRES <= 3 * OPSIZ && len == 0) | |
1067 | return 0; | |
1068 | a3 = ((op_t *) srcp1)[0]; | |
1069 | a0 = ((op_t *) srcp1)[1]; | |
1070 | b0 = ((op_t *) srcp2)[0]; | |
1071 | srcp1 += 1 * OPSIZ; | |
1072 | goto do3; | |
1073 | case 1: | |
1074 | a2 = ((op_t *) srcp1)[0]; | |
1075 | a3 = ((op_t *) srcp1)[1]; | |
1076 | b3 = ((op_t *) srcp2)[0]; | |
1077 | srcp1 += 2 * OPSIZ; | |
1078 | srcp2 += 1 * OPSIZ; | |
1079 | len -= 1; | |
1080 | if (OP_T_THRES <= 3 * OPSIZ && len == 0) | |
1081 | goto do0; | |
1082 | /* Fall through. */ | |
1083 | } | |
1084 | ||
1085 | do | |
1086 | { | |
1087 | a0 = ((op_t *) srcp1)[0]; | |
1088 | b0 = ((op_t *) srcp2)[0]; | |
1089 | x = MERGE(a2, shl, a3, shr); | |
1090 | if (x != b3) | |
1091 | return CMP_LT_OR_GT (x, b3); | |
1092 | ||
1093 | do3: | |
1094 | a1 = ((op_t *) srcp1)[1]; | |
1095 | b1 = ((op_t *) srcp2)[1]; | |
1096 | x = MERGE(a3, shl, a0, shr); | |
1097 | if (x != b0) | |
1098 | return CMP_LT_OR_GT (x, b0); | |
1099 | ||
1100 | do2: | |
1101 | a2 = ((op_t *) srcp1)[2]; | |
1102 | b2 = ((op_t *) srcp2)[2]; | |
1103 | x = MERGE(a0, shl, a1, shr); | |
1104 | if (x != b1) | |
1105 | return CMP_LT_OR_GT (x, b1); | |
1106 | ||
1107 | do1: | |
1108 | a3 = ((op_t *) srcp1)[3]; | |
1109 | b3 = ((op_t *) srcp2)[3]; | |
1110 | x = MERGE(a1, shl, a2, shr); | |
1111 | if (x != b2) | |
1112 | return CMP_LT_OR_GT (x, b2); | |
1113 | ||
1114 | srcp1 += 4 * OPSIZ; | |
1115 | srcp2 += 4 * OPSIZ; | |
1116 | len -= 4; | |
1117 | } | |
1118 | while (len != 0); | |
1119 | ||
1120 | /* This is the right position for do0. Please don't move | |
1121 | it into the loop. */ | |
1122 | do0: | |
1123 | x = MERGE(a2, shl, a3, shr); | |
1124 | if (x != b3) | |
1125 | return CMP_LT_OR_GT (x, b3); | |
1126 | return 0; | |
1127 | } | |
1128 | ||
1129 | int irc_memcmp(const __ptr_t s1, const __ptr_t s2, size_t len) | |
1130 | { | |
1131 | op_t a0; | |
1132 | op_t b0; | |
1133 | long int srcp1 = (long int) s1; | |
1134 | long int srcp2 = (long int) s2; | |
1135 | op_t res; | |
1136 | ||
1137 | if (len >= OP_T_THRES) | |
1138 | { | |
1139 | /* There are at least some bytes to compare. No need to test | |
1140 | for LEN == 0 in this alignment loop. */ | |
1141 | while (srcp2 % OPSIZ != 0) | |
1142 | { | |
1143 | a0 = ((byte *) srcp1)[0]; | |
1144 | b0 = ((byte *) srcp2)[0]; | |
1145 | srcp1 += 1; | |
1146 | srcp2 += 1; | |
1147 | res = a0 - b0; | |
1148 | if (res != 0) | |
1149 | return res; | |
1150 | len -= 1; | |
1151 | } | |
1152 | ||
1153 | /* SRCP2 is now aligned for memory operations on `op_t'. | |
1154 | SRCP1 alignment determines if we can do a simple, | |
1155 | aligned compare or need to shuffle bits. */ | |
1156 | ||
1157 | if (srcp1 % OPSIZ == 0) | |
1158 | res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ); | |
1159 | else | |
1160 | res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ); | |
1161 | if (res != 0) | |
1162 | return res; | |
1163 | ||
1164 | /* Number of bytes remaining in the interval [0..OPSIZ-1]. */ | |
1165 | srcp1 += len & -OPSIZ; | |
1166 | srcp2 += len & -OPSIZ; | |
1167 | len %= OPSIZ; | |
1168 | } | |
1169 | ||
1170 | /* There are just a few bytes to compare. Use byte memory operations. */ | |
1171 | while (len != 0) | |
1172 | { | |
1173 | a0 = ((byte *) srcp1)[0]; | |
1174 | b0 = ((byte *) srcp2)[0]; | |
1175 | srcp1 += 1; | |
1176 | srcp2 += 1; | |
1177 | res = a0 - b0; | |
1178 | if (res != 0) | |
1179 | return res; | |
1180 | len -= 1; | |
1181 | } | |
1182 | ||
1183 | return 0; | |
1184 | } | |
1185 | #endif /* HAVE_MEMCMP && MEMCMP_BROKEN */ | |
1186 |