1 /*
2 Copyright (c) 2003-2007 by Juliusz Chroboczek
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 
23 #include "polipo.h"
24 
25 /* Note that this is different from GNU's strndup(3). */
26 char *
strdup_n(const char * restrict buf,int n)27 strdup_n(const char *restrict buf, int n)
28 {
29     char *s;
30     s = malloc(n + 1);
31     if(s == NULL)
32         return NULL;
33     memcpy(s, buf, n);
34     s[n] = '\0';
35     return s;
36 }
37 
38 int
snnprintf(char * restrict buf,int n,int len,const char * format,...)39 snnprintf(char *restrict buf, int n, int len, const char *format, ...)
40 {
41     va_list args;
42     int rc;
43     va_start(args, format);
44     rc = snnvprintf(buf, n, len, format, args);
45     va_end(args);
46     return rc;
47 }
48 
49 int
snnvprintf(char * restrict buf,int n,int len,const char * format,va_list args)50 snnvprintf(char *restrict buf, int n, int len, const char *format, va_list args)
51 {
52     int rc = -1;
53     va_list args_copy;
54 
55     if(n < 0) return -2;
56     if(n < len) {
57         va_copy(args_copy, args);
58         rc = vsnprintf(buf + n, len - n, format, args_copy);
59         va_end(args_copy);
60     }
61     if(rc >= 0 && n + rc <= len)
62         return n + rc;
63     else
64         return -1;
65 }
66 
67 int
snnprint_n(char * restrict buf,int n,int len,const char * s,int slen)68 snnprint_n(char *restrict buf, int n, int len, const char *s, int slen)
69 {
70     int i = 0;
71     if(n < 0) return -2;
72     while(i < slen && n < len)
73         buf[n++] = s[i++];
74     if(n < len)
75         return n;
76     else
77         return -1;
78 }
79 
80 int
strcmp_n(const char * string,const char * buf,int n)81 strcmp_n(const char *string, const char *buf, int n)
82 {
83     int i;
84     i = 0;
85     while(string[i] != '\0' && i < n) {
86         if(string[i] < buf[i])
87             return -1;
88         else if(string[i] > buf[i])
89             return 1;
90         i++;
91     }
92     if(string[i] == '\0' || i == n)
93         return 0;
94     else if(i == n)
95         return 1;
96     else
97         return -1;
98 }
99 
100 int
letter(char c)101 letter(char c)
102 {
103     if(c >= 'A' && c <= 'Z') return 1;
104     if(c >= 'a' && c <= 'z') return 1;
105     return 0;
106 }
107 
108 int
digit(char c)109 digit(char c)
110 {
111     if(c >= '0' && c <= '9')
112         return 1;
113     return 0;
114 }
115 
116 char
lwr(char a)117 lwr(char a)
118 {
119     if(a >= 'A' && a <= 'Z')
120         return a | 0x20;
121     else
122         return a;
123 }
124 
125 char *
lwrcpy(char * restrict dst,const char * restrict src,int n)126 lwrcpy(char *restrict dst, const char *restrict src, int n)
127 {
128     int i;
129     for(i = 0; i < n; i++)
130         dst[i] = lwr(src[i]);
131     return dst;
132 }
133 
134 int
lwrcmp(const char * as,const char * bs,int n)135 lwrcmp(const char *as, const char *bs, int n)
136 {
137     int i;
138     for(i = 0; i < n; i++) {
139         char a = lwr(as[i]), b = lwr(bs[i]);
140         if(a < b)
141             return -1;
142         else if(a > b)
143             return 1;
144     }
145     return 0;
146 }
147 
148 int
strcasecmp_n(const char * string,const char * buf,int n)149 strcasecmp_n(const char *string, const char *buf, int n)
150 {
151     int i;
152     i = 0;
153     while(string[i] != '\0' && i < n) {
154         char a = lwr(string[i]), b = lwr(buf[i]);
155         if(a < b)
156             return -1;
157         else if(a > b)
158             return 1;
159         i++;
160     }
161     if(string[i] == '\0' && i == n)
162         return 0;
163     else if(i == n)
164         return 1;
165     else
166         return -1;
167 }
168 
169 int
atoi_n(const char * restrict string,int n,int len,int * value_return)170 atoi_n(const char *restrict string, int n, int len, int *value_return)
171 {
172     int i = n;
173     int val = 0;
174 
175     if(i >= len || !digit(string[i]))
176         return -1;
177 
178     while(i < len && digit(string[i])) {
179         val = val * 10 + (string[i] - '0');
180         i++;
181     }
182     *value_return = val;
183     return i;
184 }
185 
186 int
isWhitespace(const char * string)187 isWhitespace(const char *string)
188 {
189     while(*string != '\0') {
190         if(*string == ' ' || *string == '\t')
191             string++;
192         else
193             return 0;
194     }
195     return 1;
196 }
197 
198 #ifndef HAVE_MEMRCHR
199 void *
memrchr(const void * s,int c,size_t n)200 memrchr(const void *s, int c, size_t n)
201 {
202     const unsigned char *ss = s;
203     unsigned char cc = c;
204     size_t i;
205     for(i = 1; i <= n; i++)
206         if(ss[n - i] == cc)
207             return (void*)(ss + n - i);
208     return NULL;
209 }
210 #endif
211 
212 int
h2i(char h)213 h2i(char h)
214 {
215     if(h >= '0' && h <= '9')
216         return h - '0';
217     else if(h >= 'a' && h <= 'f')
218         return h - 'a' + 10;
219     else if(h >= 'A' && h <= 'F')
220         return h - 'A' + 10;
221     else
222         return -1;
223 }
224 
225 char
i2h(int i)226 i2h(int i)
227 {
228     if(i < 0 || i >= 16)
229         return '?';
230     if(i < 10)
231         return i + '0';
232     else
233         return i - 10 + 'A';
234 }
235 
236 /* floor(log2(x)) */
237 int
log2_floor(int x)238 log2_floor(int x)
239 {
240     int i, j;
241 
242     assert(x > 0);
243 
244     i = 0;
245     j = 1;
246     while(2 * j <= x) {
247         i++;
248         j *= 2;
249     }
250     return i;
251 }
252 
253 /* ceil(log2(x)) */
254 int
log2_ceil(int x)255 log2_ceil(int x)
256 {
257     int i, j;
258 
259     assert(x > 0);
260 
261     i = 0;
262     j = 1;
263     while(j < x) {
264         i++;
265         j *= 2;
266     }
267     return i;
268 }
269 
270 #ifdef HAVE_ASPRINTF
271 char *
vsprintf_a(const char * f,va_list args)272 vsprintf_a(const char *f, va_list args)
273 {
274     char *r;
275     int rc;
276     va_list args_copy;
277 
278     va_copy(args_copy, args);
279     rc = vasprintf(&r, f, args_copy);
280     va_end(args_copy);
281     if(rc < 0)
282         return NULL;
283     return r;
284 
285 }
286 
287 #else
288 
289 char*
vsprintf_a(const char * f,va_list args)290 vsprintf_a(const char *f, va_list args)
291 {
292     int n, size;
293     char buf[64];
294     char *string;
295     va_list args_copy;
296 
297     va_copy(args_copy, args);
298     n = vsnprintf(buf, 64, f, args_copy);
299     va_end(args_copy);
300     if(n >= 0 && n < 64) {
301         return strdup_n(buf, n);
302     }
303     if(n >= 64)
304         size = n + 1;
305     else
306         size = 96;
307 
308     while(1) {
309         string = malloc(size);
310         if(!string)
311             return NULL;
312         va_copy(args_copy, args);
313         n = vsnprintf(string, size, f, args_copy);
314         va_end(args_copy);
315         if(n >= 0 && n < size) {
316             return string;
317         } else if(n >= size)
318             size = n + 1;
319         else
320             size = size * 3 / 2;
321         free(string);
322         if(size > 16 * 1024)
323             return NULL;
324     }
325     /* NOTREACHED */
326 }
327 #endif
328 
329 char*
sprintf_a(const char * f,...)330 sprintf_a(const char *f, ...)
331 {
332     char *s;
333     va_list args;
334     va_start(args, f);
335     s = vsprintf_a(f, args);
336     va_end(args);
337     return s;
338 }
339 
340 unsigned int
hash(unsigned int seed,const void * restrict key,int key_size,unsigned int hash_size)341 hash(unsigned int seed, const void *restrict key, int key_size,
342      unsigned int hash_size)
343 {
344     int i;
345     unsigned int h;
346 
347     h = seed;
348     for(i = 0; i < key_size; i++)
349         h = (h << 5) + (h >> (hash_size - 5)) +
350             ((unsigned char*)key)[i];
351     return h & ((1 << hash_size) - 1);
352 }
353 
354 char *
pstrerror(int e)355 pstrerror(int e)
356 {
357     char *s;
358     static char buf[20];
359 
360     switch(e) {
361     case EDOSHUTDOWN: s = "Immediate shutdown requested"; break;
362     case EDOGRACEFUL: s = "Graceful shutdown requested"; break;
363     case EDOTIMEOUT: s = "Timeout"; break;
364     case ECLIENTRESET: s = "Connection reset by client"; break;
365     case ESYNTAX: s = "Incorrect syntax"; break;
366     case EREDIRECTOR: s = "Redirector error"; break;
367     case EDNS_HOST_NOT_FOUND: s = "Host not found"; break;
368     case EDNS_NO_ADDRESS: s = "No address"; break;
369     case EDNS_NO_RECOVERY: s = "Permanent name server failure"; break;
370     case EDNS_TRY_AGAIN: s = "Temporary name server failure"; break;
371     case EDNS_INVALID: s = "Invalid reply from name server"; break;
372     case EDNS_UNSUPPORTED: s = "Unsupported DNS reply"; break;
373     case EDNS_FORMAT: s = "Invalid DNS query"; break;
374     case EDNS_REFUSED: s = "DNS query refused by server"; break;
375     case EDNS_CNAME_LOOP: s = "DNS CNAME loop"; break;
376 #ifndef NO_SOCKS
377     case ESOCKS_PROTOCOL: s = "SOCKS protocol error"; break;
378     case ESOCKS_REJECT_FAIL: s = "SOCKS request rejected or failed"; break;
379     case ESOCKS_REJECT_IDENTD: s = "SOCKS request rejected: "
380                                    "server couldn't connect to identd";
381         break;
382     case ESOCKS_REJECT_UID_MISMATCH: s = "SOCKS request rejected: "
383                                          "uid mismatch";
384         break;
385     case ESOCKS5_BASE: s = "SOCKS success"; break;
386     case ESOCKS5_BASE + 1: s = "General SOCKS server failure"; break;
387     case ESOCKS5_BASE + 2: s = "SOCKS connection not allowed"; break;
388     case ESOCKS5_BASE + 3: s = "SOCKS error: network unreachable"; break;
389     case ESOCKS5_BASE + 4: s = "SOCKS error: host unreachable"; break;
390     case ESOCKS5_BASE + 5: s = "SOCKS error: connection refused"; break;
391     case ESOCKS5_BASE + 6: s = "SOCKS error: TTL expired"; break;
392     case ESOCKS5_BASE + 7: s = "SOCKS command not supported"; break;
393     case ESOCKS5_BASE + 8: s = "SOCKS error: address type not supported";
394         break;
395 #endif
396     case EUNKNOWN: s = "Unknown error"; break;
397     default: s = NULL; break;
398     }
399     if(!s) s = strerror(e);
400 #ifdef WIN32 /*MINGW*/
401     if(!s) {
402         if(e >= WSABASEERR && e <= WSABASEERR + 2000) {
403             /* This should be okay, as long as the caller discards the
404                pointer before another error occurs. */
405             snprintf(buf, 20, "Winsock error %d", e);
406             s = buf;
407         }
408     }
409 #endif
410     if(!s) {
411         snprintf(buf, 20, "Unknown error %d", e);
412         s = buf;
413     }
414     return s;
415 }
416 
417 /* Like mktime(3), but UTC rather than local time */
418 #if defined(HAVE_TIMEGM)
419 time_t
mktime_gmt(struct tm * tm)420 mktime_gmt(struct tm *tm)
421 {
422     return timegm(tm);
423 }
424 #elif defined(HAVE_MKGMTIME)
425 time_t
mktime_gmt(struct tm * tm)426 mktime_gmt(struct tm *tm)
427 {
428     return _mkgmtime(tm);
429 }
430 #elif defined(HAVE_TM_GMTOFF)
431 time_t
mktime_gmt(struct tm * tm)432 mktime_gmt(struct tm *tm)
433 {
434     time_t t;
435     struct tm *ltm;
436 
437     t = mktime(tm);
438     if(t < 0)
439         return -1;
440     ltm = localtime(&t);
441     if(ltm == NULL)
442         return -1;
443     return t + ltm->tm_gmtoff;
444 }
445 #elif defined(HAVE_TZSET)
446 #ifdef HAVE_SETENV
447 /* Taken from the Linux timegm(3) man page. */
448 time_t
mktime_gmt(struct tm * tm)449 mktime_gmt(struct tm *tm)
450 {
451     time_t t;
452     char *tz;
453 
454     tz = getenv("TZ");
455     setenv("TZ", "GMT", 1);
456     tzset();
457     t = mktime(tm);
458     if(tz)
459         setenv("TZ", tz, 1);
460     else
461         unsetenv("TZ");
462     tzset();
463     return t;
464 }
465 #else
466 time_t
mktime_gmt(struct tm * tm)467 mktime_gmt(struct tm *tm)
468 {
469     time_t t;
470     char *tz;
471     static char *old_tz = NULL;
472 
473     tz = getenv("TZ");
474     putenv("TZ=GMT");
475     tzset();
476     t = mktime(tm);
477     if(old_tz)
478         free(old_tz);
479     if(tz)
480         old_tz = sprintf_a("TZ=%s", tz);
481     else
482         old_tz = strdup("TZ");  /* XXX - non-portable? */
483     if(old_tz)
484         putenv(old_tz);
485     tzset();
486     return t;
487 }
488 #endif
489 #else
490 #error no mktime_gmt implementation on this platform
491 #endif
492 
493 
494 AtomPtr
expandTilde(AtomPtr filename)495 expandTilde(AtomPtr filename)
496 {
497     char *buf;
498     char *home;
499     int len;
500     AtomPtr ret;
501 
502     if(filename == NULL || filename->length < 1 ||
503        filename->string[0] != '~' || filename->string[1] != '/')
504         return filename;
505 
506     home = getenv("HOME");
507     if(home == NULL) {
508         return NULL;
509     }
510     len = strlen(home);
511     buf = malloc(len + 1 + 1 + filename->length - 2);
512     if(buf == NULL) {
513         do_log(L_ERROR, "Could not allocate buffer.\n");
514         return NULL;
515     }
516 
517     memcpy(buf, home, len);
518     if(buf[len - 1] != '/')
519         buf[len++] = '/';
520     memcpy(buf + len, filename->string + 2, filename->length - 2);
521     len += filename->length - 2;
522     ret = internAtomN(buf, len);
523     free(buf);
524     if(ret != NULL)
525         releaseAtom(filename);
526     return ret;
527 }
528 
529 #ifdef HAVE_FORK
530 void
do_daemonise(int noclose)531 do_daemonise(int noclose)
532 {
533     int rc;
534 
535     fflush(stdout);
536     fflush(stderr);
537 
538     rc = fork();
539     if(rc < 0) {
540         do_log_error(L_ERROR, errno, "Couldn't fork");
541         exit(1);
542     }
543 
544     if(rc > 0)
545         exit(0);
546 
547     if(!noclose) {
548         int fd;
549         close(0);
550         close(1);
551         close(2);
552         /* Leaving the default file descriptors free is not a good
553            idea, as it will cause library functions such as abort to
554            thrash the on-disk cache. */
555         fd = open("/dev/null", O_RDONLY);
556         if(fd > 0) {
557             dup2(fd, 0);
558             close(fd);
559         }
560         fd = open("/dev/null", O_WRONLY);
561         if(fd >= 0) {
562             if(fd != 1)
563                 dup2(fd, 1);
564             if(fd != 2)
565                 dup2(fd, 2);
566             if(fd != 1 && fd != 2)
567                 close(fd);
568         }
569     }
570     rc = setsid();
571     if(rc < 0) {
572         do_log_error(L_ERROR, errno, "Couldn't create new session");
573         exit(1);
574     }
575 }
576 
577 #elif defined(WIN32)
578 
579 void
do_daemonise(int noclose)580 do_daemonise(int noclose)
581 {
582 	do_log(L_INFO, "Detaching console");
583 	FreeConsole();
584 }
585 
586 #else
587 
588 void
do_daemonise(int noclose)589 do_daemonise(int noclose)
590 {
591     do_log(L_ERROR, "Cannot daemonise on this platform");
592     exit(1);
593 }
594 #endif
595 
596 
597 void
writePid(char * pidfile)598 writePid(char *pidfile)
599 {
600     int fd, n, rc;
601     char buf[16];
602 
603     fd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
604     if(fd < 0) {
605         do_log_error(L_ERROR, errno,
606                      "Couldn't create pid file %s", pidfile);
607         exit(1);
608     }
609     n = snprintf(buf, 16, "%ld\n", (long)getpid());
610     if(n < 0 || n >= 16) {
611         close(fd);
612         unlink(pidfile);
613         do_log(L_ERROR, "Couldn't format pid.\n");
614         exit(1);
615     }
616     rc = write(fd, buf, n);
617     if(rc != n) {
618         close(fd);
619         unlink(pidfile);
620         do_log_error(L_ERROR, errno, "Couldn't write pid");
621         exit(1);
622     }
623 
624     close(fd);
625     return;
626 }
627 
628 static const char b64[64] =
629 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
630 
631 /* "/" replaced with "-" */
632 static const char b64fss[64] =
633 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
634 
635 int
b64cpy(char * restrict dst,const char * restrict src,int n,int fss)636 b64cpy(char *restrict dst, const char *restrict src, int n, int fss)
637 {
638     const char *b = fss ? b64fss: b64;
639     int i, j;
640 
641     j = 0;
642     for(i = 0; i < n; i += 3) {
643         unsigned char a0, a1, a2;
644         a0 = src[i];
645         a1 = i < n - 1 ? src[i + 1] : 0;
646         a2 = i < n - 2 ? src[i + 2] : 0;
647         dst[j++] = b[(a0 >> 2) & 0x3F];
648         dst[j++] = b[((a0 << 4) & 0x30) | ((a1 >> 4) & 0x0F)];
649         if(i < n - 1)
650             dst[j++] = b[((a1 << 2) & 0x3C) | ((a2 >> 6) & 0x03)];
651         else
652             dst[j++] = '=';
653         if(i < n - 2)
654             dst[j++] = b[a2 & 0x3F];
655         else
656             dst[j++] = '=';
657     }
658     return j;
659 }
660 
661 int
b64cmp(const char * restrict a,int an,const char * restrict b,int bn)662 b64cmp(const char *restrict a, int an, const char *restrict b, int bn)
663 {
664     char *buf;
665     int r;
666 
667     if(an % 4 != 0)
668         return -1;
669     if((bn + 2) / 3 != an / 4)
670         return -1;
671     buf = malloc(an);
672     if(buf == NULL)
673         return -1;
674     b64cpy(buf, b, bn, 0);
675     r = memcmp(buf, a, an);
676     free(buf);
677     return r;
678 }
679 
680 IntListPtr
makeIntList(int size)681 makeIntList(int size)
682 {
683     IntListPtr list;
684     if(size <= 0)
685         size = 4;
686 
687     list = malloc(sizeof(IntListRec));
688     if(list == NULL)
689         return NULL;
690 
691     list->ranges = malloc(size * sizeof(IntRangeRec));
692     if(list->ranges == NULL) {
693         free(list);
694         return NULL;
695     }
696 
697     list->length = 0;
698     list->size = size;
699     return list;
700 }
701 
702 void
destroyIntList(IntListPtr list)703 destroyIntList(IntListPtr list)
704 {
705     free(list->ranges);
706     free(list);
707 }
708 
709 int
intListMember(int n,IntListPtr list)710 intListMember(int n, IntListPtr list)
711 {
712     int lo = 0, hi = list->length - 1;
713     int mid;
714     while(hi >= lo) {
715         mid = (hi + lo) / 2;
716         if(list->ranges[mid].from > n)
717             hi = mid - 1;
718         else if(list->ranges[mid].to < n)
719             lo = mid + 1;
720         else
721             return 1;
722     }
723     return 0;
724 }
725 
726 static int
deleteRange(IntListPtr list,int i)727 deleteRange(IntListPtr list, int i)
728 {
729     assert(list->length > i);
730     if(list->length > i + 1)
731         memmove(list->ranges + i, list->ranges + i + 1,
732                 (list->length - i - 1) * sizeof(IntRangeRec));
733     list->length--;
734     return 1;
735 }
736 
737 static int
insertRange(int from,int to,IntListPtr list,int i)738 insertRange(int from, int to, IntListPtr list, int i)
739 {
740     assert(i >= 0 && i <= list->length);
741     assert(i == 0 || list->ranges[i - 1].to < from - 1);
742     assert(i == list->length || list->ranges[i].from > to + 1);
743 
744     if(list->length >= list->size) {
745         int newsize = list->size * 2 + 1;
746         IntRangePtr newranges =
747             realloc(list->ranges, newsize * sizeof(IntRangeRec));
748         if(newranges == NULL)
749             return -1;
750         list->size = newsize;
751         list->ranges = newranges;
752     }
753 
754     if(i < list->length)
755         memmove(list->ranges + i + 1, list->ranges + i,
756                 list->length - i);
757     list->length++;
758     list->ranges[i].from = from;
759     list->ranges[i].to = to;
760     return 1;
761 }
762 
763 static int
maybeMergeRanges(IntListPtr list,int i)764 maybeMergeRanges(IntListPtr list, int i)
765 {
766     int rc;
767 
768     while(i > 0 && list->ranges[i].from <= list->ranges[i - 1].to + 1) {
769             list->ranges[i - 1].from =
770                 MIN(list->ranges[i - 1].from, list->ranges[i].from);
771             list->ranges[i - 1].to =
772                 MAX(list->ranges[i - 1].to, list->ranges[i].to);
773             rc = deleteRange(list, i);
774             if(rc < 0) return -1;
775             i--;
776     }
777 
778     while(i < list->length - 1 &&
779           list->ranges[i].to >= list->ranges[i + 1].from - 1) {
780             list->ranges[i + 1].from =
781                 MIN(list->ranges[i + 1].from, list->ranges[i].from);
782             list->ranges[i - 1].to =
783                 MAX(list->ranges[i + 1].to, list->ranges[i].to);
784             rc = deleteRange(list, i);
785             if(rc < 0) return -1;
786     }
787     return 1;
788 }
789 
790 int
intListCons(int from,int to,IntListPtr list)791 intListCons(int from, int to, IntListPtr list)
792 {
793     int i;
794 
795     /* Don't bother with the dichotomy. */
796     for(i = 0; i < list->length; i++) {
797         if(list->ranges[i].to >= from - 1)
798             break;
799     }
800 
801     if(i < list->length &&
802        (from >= list->ranges[i].from - 1 || to <= list->ranges[i].to + 1)) {
803         if(from <= list->ranges[i].from)
804             list->ranges[i].from = from;
805         if(to >= list->ranges[i].to)
806             list->ranges[i].to = to;
807         return maybeMergeRanges(list, i);
808     }
809     return insertRange(from, to, list, i);
810 }
811 
812 /* Return the amount of physical memory on the box, -1 if unknown or
813    over two gigs. */
814 #if defined(__linux__)
815 
816 #include <sys/sysinfo.h>
817 int
physicalMemory()818 physicalMemory()
819 {
820     int rc;
821     struct sysinfo info;
822 
823     rc = sysinfo(&info);
824     if(rc < 0)
825         return -1;
826 
827     if(info.totalram <= 0x7fffffff / info.mem_unit)
828         return (int)(info.totalram * info.mem_unit);
829 
830     return -1;
831 }
832 
833 #elif defined(__FreeBSD__)
834 
835 #include <sys/sysctl.h>
836 int
physicalMemory()837 physicalMemory()
838 {
839     unsigned long membytes;
840     size_t len;
841     int res;
842 
843     len = sizeof(membytes);
844     res = sysctlbyname("hw.physmem", &membytes, &len, NULL, 0);
845     if (res || membytes > INT_MAX)
846         return -1;
847 
848     return (int)membytes;
849 }
850 
851 #else
852 
853 int
physicalMemory()854 physicalMemory()
855 {
856     return -1;
857 }
858 #endif
859