]> jfr.im git - irc.git/blame - software/ircd/www.irc.org/ftp/irc/server/irc2.11.2p3/common/support.c
init
[irc.git] / software / ircd / www.irc.org / ftp / irc / server / irc2.11.2p3 / common / support.c
CommitLineData
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
21static 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
31char ipv6string[INET6_ADDRSTRLEN];
32#endif
33
34unsigned char minus_one[]={ 255, 255, 255, 255, 255, 255, 255, 255, 255,
35 255, 255, 255, 255, 255, 255, 255, 0};
36
37
38char *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
63char *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
127char *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
143char *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
172char *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*/
188char *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 */
205char *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*/
287int 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
317char *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*/
338int 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 */
359u_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 */
377int 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)
470void 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
514static char *marray[100000];
515static 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
522char *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
555char *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
604void 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
637char *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
653char *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*/
683int 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;
703dgetsagain:
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 */
718dgetsreturnbuf:
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 */
782char *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 */
802char **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 */
838int 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
858struct 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. */
888typedef 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
922static 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
946static 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
1030static 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
1129int 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