Quell a GCC warning about a NULL format string on FreeBSD.
[polipo.git] / util.c
blob727fc4e3147b4788b4fa5d0ac481cd29dcb91f4e
1 /*
2 Copyright (c) 2003-2007 by Juliusz Chroboczek
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:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
23 #include "polipo.h"
25 /* Note that this is different from GNU's strndup(3). */
26 char *
27 strdup_n(const char *restrict buf, int n)
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;
38 int
39 snnprintf(char *restrict buf, int n, int len, const char *format, ...)
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;
49 int
50 snnvprintf(char *restrict buf, int n, int len, const char *format, va_list args)
52 int rc = -1;
53 if(n < 0) return -2;
54 if(n < len)
55 rc = vsnprintf(buf + n, len - n, format, args);
56 if(rc >= 0 && n + rc <= len)
57 return n + rc;
58 else
59 return -1;
62 int
63 snnprint_n(char *restrict buf, int n, int len, const char *s, int slen)
65 int i = 0;
66 if(n < 0) return -2;
67 while(i < slen && n < len)
68 buf[n++] = s[i++];
69 if(n < len)
70 return n;
71 else
72 return -1;
75 int
76 strcmp_n(const char *string, const char *buf, int n)
78 int i;
79 i = 0;
80 while(string[i] != '\0' && i < n) {
81 if(string[i] < buf[i])
82 return -1;
83 else if(string[i] > buf[i])
84 return 1;
85 i++;
87 if(string[i] == '\0' || i == n)
88 return 0;
89 else if(i == n)
90 return 1;
91 else
92 return -1;
95 int
96 letter(char c)
98 if(c >= 'A' && c <= 'Z') return 1;
99 if(c >= 'a' && c <= 'z') return 1;
100 return 0;
104 digit(char c)
106 if(c >= '0' && c <= '9')
107 return 1;
108 return 0;
111 char
112 lwr(char a)
114 if(a >= 'A' && a <= 'Z')
115 return a | 0x20;
116 else
117 return a;
120 char *
121 lwrcpy(char *restrict dst, const char *restrict src, int n)
123 int i;
124 for(i = 0; i < n; i++)
125 dst[i] = lwr(src[i]);
126 return dst;
130 lwrcmp(const char *as, const char *bs, int n)
132 int i;
133 for(i = 0; i < n; i++) {
134 char a = lwr(as[i]), b = lwr(bs[i]);
135 if(a < b)
136 return -1;
137 else if(a > b)
138 return 1;
140 return 0;
144 strcasecmp_n(const char *string, const char *buf, int n)
146 int i;
147 i = 0;
148 while(string[i] != '\0' && i < n) {
149 char a = lwr(string[i]), b = lwr(buf[i]);
150 if(a < b)
151 return -1;
152 else if(a > b)
153 return 1;
154 i++;
156 if(string[i] == '\0' && i == n)
157 return 0;
158 else if(i == n)
159 return 1;
160 else
161 return -1;
165 parseIntN(const char *restrict str, int m, int n, int min, int max,
166 int base, int *value_return)
168 char buf[64];
169 char *endp;
170 long val;
171 size_t len;
173 while (m < n && (str[m] == ' ' || str[m] == '\t'))
174 m++;
176 if (m >= n)
177 return -1;
179 /* We hope here that 63 bytes is more than enough to hold
180 a number that won't overflow. */
181 len = MIN(n - m, sizeof(buf) - 1);
182 memcpy(buf, str + m, len);
183 buf[len] = '\0';
185 errno = 0;
186 val = strtol(buf, &endp, base);
187 if (errno != 0 || endp == buf || val < min || val > max)
188 return -1;
190 m += endp - buf;
192 *value_return = val;
193 return m;
197 parseInt(const char *restrict str, int m, int min, int max,
198 int base, int *value_return)
200 char *endp;
201 long val;
203 errno = 0;
204 val = strtol(str + m, &endp, base);
205 if (errno != 0 || endp == str + m || val < min || val > max)
206 return -1;
208 m = endp - str;
210 *value_return = val;
211 return m;
214 int
215 isWhitespace(const char *string)
217 while(*string != '\0') {
218 if(*string == ' ' || *string == '\t')
219 string++;
220 else
221 return 0;
223 return 1;
226 #ifndef HAVE_MEMRCHR
227 void *
228 memrchr(const void *s, int c, size_t n)
230 const unsigned char *ss = s;
231 unsigned char cc = c;
232 size_t i;
233 for(i = n - 1; i >= 0; i--)
234 if(ss[i] == cc)
235 return (void*)(ss + i);
236 return NULL;
238 #endif
241 h2i(char h)
243 if(h >= '0' && h <= '9')
244 return h - '0';
245 else if(h >= 'a' && h <= 'f')
246 return h - 'a' + 10;
247 else if(h >= 'A' && h <= 'F')
248 return h - 'A' + 10;
249 else
250 return -1;
253 char
254 i2h(int i)
256 if(i < 0 || i >= 16)
257 return '?';
258 if(i < 10)
259 return i + '0';
260 else
261 return i - 10 + 'A';
264 /* floor(log2(x)) */
266 log2_floor(int x)
268 int i, j;
270 assert(x > 0);
272 i = 0;
273 j = 1;
274 while(2 * j <= x) {
275 i++;
276 j *= 2;
278 return i;
281 /* ceil(log2(x)) */
283 log2_ceil(int x)
285 int i, j;
287 assert(x > 0);
289 i = 0;
290 j = 1;
291 while(j < x) {
292 i++;
293 j *= 2;
295 return i;
298 #ifdef HAVE_ASPRINTF
299 char *
300 vsprintf_a(const char *f, va_list args)
302 char *r;
303 int rc;
305 rc = vasprintf(&r, f, args);
306 if(rc < 0)
307 return NULL;
308 return r;
312 #else
314 /* This is not going to work if va_list is interesting. But then, if you
315 have a non-trivial implementation of va_list, you should have va_copy. */
316 #ifndef va_copy
317 #define va_copy(a, b) do { a = b; } while(0)
318 #endif
320 char*
321 vsprintf_a(const char *f, va_list args)
323 int n, size;
324 char buf[64];
325 char *string;
326 va_list args_copy;
328 va_copy(args_copy, args);
329 n = vsnprintf(buf, 64, f, args_copy);
330 if(n >= 0 && n < 64) {
331 return strdup_n(buf, n);
333 if(n >= 64)
334 size = n + 1;
335 else
336 size = 96;
338 while(1) {
339 string = malloc(size);
340 if(!string)
341 return NULL;
342 va_copy(args_copy, args);
343 n = vsnprintf(string, size, f, args_copy);
344 if(n >= 0 && n < size)
345 return string;
346 else if(n >= size)
347 size = n + 1;
348 else
349 size = size * 3 / 2;
350 free(string);
351 if(size > 16 * 1024)
352 return NULL;
354 /* NOTREACHED */
356 #endif
358 char*
359 sprintf_a(const char *f, ...)
361 char *s;
362 va_list args;
363 va_start(args, f);
364 s = vsprintf_a(f, args);
365 va_end(args);
366 return s;
369 unsigned int
370 hash(unsigned int seed, const void *restrict key, int key_size,
371 unsigned int hash_size)
373 int i;
374 unsigned int h;
376 h = seed;
377 for(i = 0; i < key_size; i++)
378 h = (h << 5) + (h >> (hash_size - 5)) +
379 ((unsigned char*)key)[i];
380 return h & ((1 << hash_size) - 1);
383 char *
384 pstrerror(int e)
386 char *s;
387 static char buf[20];
389 switch(e) {
390 case EDOSHUTDOWN: s = "Immediate shutdown requested"; break;
391 case EDOGRACEFUL: s = "Graceful shutdown requested"; break;
392 case EDOTIMEOUT: s = "Timeout"; break;
393 case ECLIENTRESET: s = "Connection reset by client"; break;
394 case ESYNTAX: s = "Incorrect syntax"; break;
395 case EREDIRECTOR: s = "Redirector error"; break;
396 case EDNS_HOST_NOT_FOUND: s = "Host not found"; break;
397 case EDNS_NO_ADDRESS: s = "No address"; break;
398 case EDNS_NO_RECOVERY: s = "Permanent name server failure"; break;
399 case EDNS_TRY_AGAIN: s = "Temporary name server failure"; break;
400 case EDNS_INVALID: s = "Invalid reply from name server"; break;
401 case EDNS_UNSUPPORTED: s = "Unsupported DNS reply"; break;
402 case EDNS_FORMAT: s = "Invalid DNS query"; break;
403 case EDNS_REFUSED: s = "DNS query refused by server"; break;
404 case EDNS_CNAME_LOOP: s = "DNS CNAME loop"; break;
405 #ifndef NO_SOCKS
406 case ESOCKS_PROTOCOL: s = "SOCKS protocol error"; break;
407 case ESOCKS_REJECT_FAIL: s = "SOCKS request rejected or failed"; break;
408 case ESOCKS_REJECT_IDENTD: s = "SOCKS request rejected: "
409 "server couldn't connect to identd";
410 break;
411 case ESOCKS_REJECT_UID_MISMATCH: s = "SOCKS request rejected: "
412 "uid mismatch";
413 break;
414 case ESOCKS5_BASE: s = "SOCKS success"; break;
415 case ESOCKS5_BASE + 1: s = "General SOCKS server failure"; break;
416 case ESOCKS5_BASE + 2: s = "SOCKS connection not allowed"; break;
417 case ESOCKS5_BASE + 3: s = "SOCKS error: network unreachable"; break;
418 case ESOCKS5_BASE + 4: s = "SOCKS error: host unreachable"; break;
419 case ESOCKS5_BASE + 5: s = "SOCKS error: connection refused"; break;
420 case ESOCKS5_BASE + 6: s = "SOCKS error: TTL expired"; break;
421 case ESOCKS5_BASE + 7: s = "SOCKS command not supported"; break;
422 case ESOCKS5_BASE + 8: s = "SOCKS error: address type not supported";
423 break;
424 #endif
425 case EUNKNOWN: s = "Unknown error"; break;
426 default: s = NULL; break;
428 if(!s) s = strerror(e);
429 #ifdef WIN32 /*MINGW*/
430 if(!s) {
431 if(e >= WSABASEERR && e <= WSABASEERR + 2000) {
432 /* This should be okay, as long as the caller discards the
433 pointer before another error occurs. */
434 snprintf(buf, 20, "Winsock error %d", e);
435 s = buf;
438 #endif
439 if(!s) {
440 snprintf(buf, 20, "Unknown error %d", e);
441 s = buf;
443 return s;
446 /* Like mktime(3), but UTC rather than local time */
447 #if defined(HAVE_TIMEGM)
448 time_t
449 mktime_gmt(struct tm *tm)
451 return timegm(tm);
453 #elif defined(HAVE_TM_GMTOFF)
454 time_t
455 mktime_gmt(struct tm *tm)
457 time_t t;
458 struct tm *ltm;
460 t = mktime(tm);
461 if(t < 0)
462 return -1;
463 ltm = localtime(&t);
464 if(ltm == NULL)
465 return -1;
466 return t + ltm->tm_gmtoff;
468 #elif defined(HAVE_TZSET)
469 #ifdef HAVE_SETENV
470 /* Taken from the Linux timegm(3) man page. */
471 time_t
472 mktime_gmt(struct tm *tm)
474 time_t t;
475 char *tz;
477 tz = getenv("TZ");
478 setenv("TZ", "GMT", 1);
479 tzset();
480 t = mktime(tm);
481 if(tz)
482 setenv("TZ", tz, 1);
483 else
484 unsetenv("TZ");
485 tzset();
486 return t;
488 #else
489 time_t
490 mktime_gmt(struct tm *tm)
492 time_t t;
493 char *tz;
494 static char *old_tz = NULL;
496 tz = getenv("TZ");
497 putenv("TZ=GMT");
498 tzset();
499 t = mktime(tm);
500 if(old_tz)
501 free(old_tz);
502 if(tz)
503 old_tz = sprintf_a("TZ=%s", tz);
504 else
505 old_tz = strdup("TZ"); /* XXX - non-portable? */
506 if(old_tz)
507 putenv(old_tz);
508 tzset();
509 return t;
511 #endif
512 #else
513 #error no mktime_gmt implementation on this platform
514 #endif
517 AtomPtr
518 expandTilde(AtomPtr filename)
520 char *buf;
521 char *home;
522 int len;
523 AtomPtr ret;
525 if(filename == NULL || filename->length < 1 ||
526 filename->string[0] != '~' || filename->string[1] != '/')
527 return filename;
529 home = getenv("HOME");
530 if(home == NULL) {
531 return NULL;
533 len = strlen(home);
534 buf = malloc(len + 1 + 1 + filename->length - 2);
535 if(buf == NULL) {
536 do_log(L_ERROR, "Could not allocate buffer.\n");
537 return NULL;
540 memcpy(buf, home, len);
541 if(buf[len - 1] != '/')
542 buf[len++] = '/';
543 memcpy(buf + len, filename->string + 2, filename->length - 2);
544 len += filename->length - 2;
545 ret = internAtomN(buf, len);
546 free(buf);
547 if(ret != NULL)
548 releaseAtom(filename);
549 return ret;
552 #ifdef HAVE_FORK
553 void
554 do_daemonise(int noclose)
556 int rc;
558 fflush(stdout);
559 fflush(stderr);
561 rc = fork();
562 if(rc < 0) {
563 do_log_error(L_ERROR, errno, "Couldn't fork");
564 exit(1);
567 if(rc > 0)
568 exit(0);
570 if(!noclose) {
571 int fd;
572 close(0);
573 close(1);
574 close(2);
575 /* Leaving the default file descriptors free is not a good
576 idea, as it will cause library functions such as abort to
577 thrash the on-disk cache. */
578 fd = open("/dev/null", O_RDONLY);
579 if(fd > 0) {
580 dup2(fd, 0);
581 close(fd);
583 fd = open("/dev/null", O_WRONLY);
584 if(fd >= 0) {
585 if(fd != 1)
586 dup2(fd, 1);
587 if(fd != 2)
588 dup2(fd, 2);
589 if(fd != 1 && fd != 2)
590 close(fd);
593 rc = setsid();
594 if(rc < 0) {
595 do_log_error(L_ERROR, errno, "Couldn't create new session");
596 exit(1);
600 #else
602 void
603 do_daemonise(int noclose)
605 do_log(L_ERROR, "Cannot daemonise on this platform");
606 exit(1);
608 #endif
611 void
612 writePid(char *pidfile)
614 int fd, n, rc;
615 char buf[16];
617 fd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
618 if(fd < 0) {
619 do_log_error(L_ERROR, errno,
620 "Couldn't create pid file %s", pidfile);
621 exit(1);
623 n = snprintf(buf, 16, "%ld\n", (long)getpid());
624 if(n < 0 || n >= 16) {
625 close(fd);
626 unlink(pidfile);
627 do_log(L_ERROR, "Couldn't format pid.\n");
628 exit(1);
630 rc = write(fd, buf, n);
631 if(rc != n) {
632 close(fd);
633 unlink(pidfile);
634 do_log_error(L_ERROR, errno, "Couldn't write pid");
635 exit(1);
638 close(fd);
639 return;
642 static const char b64[64] =
643 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
645 /* "/" replaced with "-" */
646 static const char b64fss[64] =
647 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
650 b64cpy(char *restrict dst, const char *restrict src, int n, int fss)
652 const char *b = fss ? b64fss: b64;
653 int i, j;
655 j = 0;
656 for(i = 0; i < n; i += 3) {
657 unsigned char a0, a1, a2;
658 a0 = src[i];
659 a1 = i < n - 1 ? src[i + 1] : 0;
660 a2 = i < n - 2 ? src[i + 2] : 0;
661 dst[j++] = b[(a0 >> 2) & 0x3F];
662 dst[j++] = b[((a0 << 4) & 0x30) | ((a1 >> 4) & 0x0F)];
663 if(i < n - 1)
664 dst[j++] = b[((a1 << 2) & 0x3C) | ((a2 >> 6) & 0x03)];
665 else
666 dst[j++] = '=';
667 if(i < n - 2)
668 dst[j++] = b[a2 & 0x3F];
669 else
670 dst[j++] = '=';
672 return j;
676 b64cmp(const char *restrict a, int an, const char *restrict b, int bn)
678 char *buf;
679 int r;
681 if(an % 4 != 0)
682 return -1;
683 if((bn + 2) / 3 != an / 4)
684 return -1;
685 buf = malloc(an);
686 if(buf == NULL)
687 return -1;
688 b64cpy(buf, b, bn, 0);
689 r = memcmp(buf, a, an);
690 free(buf);
691 return r;
694 IntListPtr
695 makeIntList(int size)
697 IntListPtr list;
698 if(size <= 0)
699 size = 4;
701 list = malloc(sizeof(IntListRec));
702 if(list == NULL)
703 return NULL;
705 list->ranges = malloc(size * sizeof(IntRangeRec));
706 if(list->ranges == NULL) {
707 free(list);
708 return NULL;
711 list->length = 0;
712 list->size = size;
713 return list;
716 void
717 destroyIntList(IntListPtr list)
719 free(list->ranges);
720 free(list);
724 intListMember(int n, IntListPtr list)
726 int lo = 0, hi = list->length - 1;
727 int mid;
728 while(hi >= lo) {
729 mid = (hi + lo) / 2;
730 if(list->ranges[mid].from > n)
731 hi = mid - 1;
732 else if(list->ranges[mid].to < n)
733 lo = mid + 1;
734 else
735 return 1;
737 return 0;
740 static int
741 deleteRange(IntListPtr list, int i)
743 assert(list->length > i);
744 if(list->length > i + 1)
745 memmove(list->ranges + i, list->ranges + i + 1,
746 (list->length - i - 1) * sizeof(IntRangeRec));
747 list->length--;
748 return 1;
751 static int
752 insertRange(int from, int to, IntListPtr list, int i)
754 assert(i >= 0 && i <= list->length);
755 assert(i == 0 || list->ranges[i - 1].to < from - 1);
756 assert(i == list->length || list->ranges[i].from > to + 1);
758 if(list->length >= list->size) {
759 int newsize = list->size * 2 + 1;
760 IntRangePtr newranges =
761 realloc(list->ranges, newsize * sizeof(IntRangeRec));
762 if(newranges == NULL)
763 return -1;
764 list->size = newsize;
765 list->ranges = newranges;
768 if(i < list->length)
769 memmove(list->ranges + i + 1, list->ranges + i,
770 list->length - i);
771 list->length++;
772 list->ranges[i].from = from;
773 list->ranges[i].to = to;
774 return 1;
777 static int
778 maybeMergeRanges(IntListPtr list, int i)
780 int rc;
782 while(i > 0 && list->ranges[i].from <= list->ranges[i - 1].to + 1) {
783 list->ranges[i - 1].from =
784 MIN(list->ranges[i - 1].from, list->ranges[i].from);
785 list->ranges[i - 1].to =
786 MAX(list->ranges[i - 1].to, list->ranges[i].to);
787 rc = deleteRange(list, i);
788 if(rc < 0) return -1;
789 i--;
792 while(i < list->length - 1 &&
793 list->ranges[i].to >= list->ranges[i + 1].from - 1) {
794 list->ranges[i + 1].from =
795 MIN(list->ranges[i + 1].from, list->ranges[i].from);
796 list->ranges[i - 1].to =
797 MAX(list->ranges[i + 1].to, list->ranges[i].to);
798 rc = deleteRange(list, i);
799 if(rc < 0) return -1;
801 return 1;
805 intListCons(int from, int to, IntListPtr list)
807 int i;
809 /* Don't bother with the dichotomy. */
810 for(i = 0; i < list->length; i++) {
811 if(list->ranges[i].to >= from - 1)
812 break;
815 if(i < list->length &&
816 (from >= list->ranges[i].from - 1 || to <= list->ranges[i].to + 1)) {
817 if(from <= list->ranges[i].from)
818 list->ranges[i].from = from;
819 if(to >= list->ranges[i].to)
820 list->ranges[i].to = to;
821 return maybeMergeRanges(list, i);
823 return insertRange(from, to, list, i);
826 /* Return the amount of physical memory on the box, -1 if unknown or
827 over two gigs. */
828 #if defined(__linux__)
830 #include <sys/sysinfo.h>
832 physicalMemory()
834 int rc;
835 struct sysinfo info;
837 rc = sysinfo(&info);
838 if(rc < 0)
839 return -1;
841 if(info.totalram <= 0x7fffffff / info.mem_unit)
842 return (int)(info.totalram * info.mem_unit);
844 return -1;
847 #elif defined(__FreeBSD__)
849 #include <sys/sysctl.h>
851 physicalMemory()
853 unsigned long membytes;
854 size_t len;
855 int res;
857 len = sizeof(membytes);
858 res = sysctlbyname("hw.physmem", &membytes, &len, NULL, 0);
859 if (res || membytes > INT_MAX)
860 return -1;
862 return (int)membytes;
865 #else
868 physicalMemory()
870 return -1;
872 #endif