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