summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2017-12-27 19:37:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2017-12-27 19:38:01 +0000
commitae0d162540c112860c65dbb4860a2318b0ea4364 (patch)
treeddcbd96da9654b17b0763ccbce0b751385f64c56
parentReleasing progress-linux version 2.4.0-1~dschinn1. (diff)
downloadgeoipupdate-ae0d162540c112860c65dbb4860a2318b0ea4364.zip
geoipupdate-ae0d162540c112860c65dbb4860a2318b0ea4364.tar.xz
Merging upstream version 2.5.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--ChangeLog.md20
-rw-r--r--README.md12
-rw-r--r--bin/Makefile.am3
-rw-r--r--bin/Makefile.in8
-rw-r--r--bin/base64.c575
-rw-r--r--bin/base64.h67
-rw-r--r--bin/edition_s.c48
-rw-r--r--bin/functions.c172
-rw-r--r--bin/functions.h6
-rw-r--r--bin/geoipupdate-pureperl.pl32
-rw-r--r--bin/geoipupdate.c452
-rw-r--r--bin/geoipupdate.h53
-rw-r--r--bin/geoipupdate_s.c22
-rw-r--r--bin/md5.c143
-rw-r--r--bin/md5.h9
-rw-r--r--bin/product_s.c54
-rw-r--r--bin/types.h21
-rw-r--r--conf/GeoIP.conf.default20
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac2
-rw-r--r--man/GeoIP.conf.5.in29
21 files changed, 639 insertions, 1129 deletions
diff --git a/ChangeLog.md b/ChangeLog.md
index 6c68aae..3a35fc7 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,26 @@
GeoIP Update Change Log
=======================
+2.5.0 (2017-10-30)
+------------------
+
+* Replace use of strnlen() due to lack of universal availability. First
+ reported by Bill Cole. GitHub issue #71.
+* Document the `LockFile` option in the `GeoIP.conf` man page. GitHub
+ issue #64.
+* Remove unused base64 library. PR by Mikhail Teterin. GitHub PR #68.
+* Add the new configuration option `PreserveFileTimes`. If set,
+ the downloaded files will get the same modification times as
+ their original on the server. Default is `0` (unset).
+ PR by Rainer Jung. GitHub PR #63.
+* Use the correct types when calling `curl_easy_setopt()`. This fixes
+ warnings generated by libcurl's `typecheck-gcc.h`. PR by Michael
+ Kaufmann. GitHub PR #61.
+* In `GeoIP.conf`, the `UserId` option was renamed to `AccountID` and the
+ `ProductIds` option was renamed to `EditionIDs`. The old options will
+ continue to work, but upgrading to the new names is recommended for
+ forward compatibility.
+
2.4.0 (2017-05-25)
------------------
diff --git a/README.md b/README.md
index 5f944db..a79a6d2 100644
--- a/README.md
+++ b/README.md
@@ -22,11 +22,19 @@ Then install `geoipupdate` by running:
## Installing From Source File
To install this from the source package, you will need a C compiler, Make,
-the zlib library and headers, and the curl library and headers. On Debian
-or Ubuntu, you can install these dependencies by running:
+the zlib library and headers, and the curl library and headers.
+
+On Debian or Ubuntu, you can install these
+dependencies by running:
$ sudo apt-get install build-essential libcurl4-openssl-dev zlib1g-dev
+On Centos 7 or RHEL 7, you can install these
+dependencies by running:
+
+ $ sudo yum groupinstall 'Development Tools'
+ $ sudo yum install libcurl-devel
+
Once you have the necessary dependencies, run the following commands:
$ ./configure
diff --git a/bin/Makefile.am b/bin/Makefile.am
index 345ac55..b7a781d 100644
--- a/bin/Makefile.am
+++ b/bin/Makefile.am
@@ -6,9 +6,8 @@ bin_PROGRAMS = geoipupdate
geoipupdate_SOURCES = \
geoipupdate.c geoipupdate.h \
md5.c md5.h \
- base64.c base64.h \
geoipupdate_s.c \
- product_s.c \
+ edition_s.c \
types.h \
functions.c functions.h
geoipupdate_LDFLAGS =
diff --git a/bin/Makefile.in b/bin/Makefile.in
index 2f1b39b..9439ef6 100644
--- a/bin/Makefile.in
+++ b/bin/Makefile.in
@@ -110,7 +110,7 @@ am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
am_geoipupdate_OBJECTS = geoipupdate.$(OBJEXT) md5.$(OBJEXT) \
- base64.$(OBJEXT) geoipupdate_s.$(OBJEXT) product_s.$(OBJEXT) \
+ geoipupdate_s.$(OBJEXT) edition_s.$(OBJEXT) \
functions.$(OBJEXT)
geoipupdate_OBJECTS = $(am_geoipupdate_OBJECTS)
geoipupdate_DEPENDENCIES =
@@ -507,9 +507,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/src -DSYSCONFDIR=\"$(sysconfdir)\" -DDATADIR=\"$(d
geoipupdate_SOURCES = \
geoipupdate.c geoipupdate.h \
md5.c md5.h \
- base64.c base64.h \
geoipupdate_s.c \
- product_s.c \
+ edition_s.c \
types.h \
functions.c functions.h
@@ -624,13 +623,12 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/edition_s.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/functions.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/functions_test-functions.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geoipupdate.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geoipupdate_s.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/product_s.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/bin/base64.c b/bin/base64.c
deleted file mode 100644
index 2c8780d..0000000
--- a/bin/base64.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/* base64.c -- Encode binary data using printable characters.
- Copyright (C) 1999-2001, 2004-2006, 2009-2012 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-/* Written by Simon Josefsson. Partially adapted from GNU MailUtils
- * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review
- * from Paul Eggert, Bruno Haible, and Stepan Kasal.
- *
- * See also RFC 4648 <http://www.ietf.org/rfc/rfc4648.txt>.
- *
- * Be careful with error checking. Here is how you would typically
- * use these functions:
- *
- * bool ok = base64_decode_alloc (in, inlen, &out, &outlen);
- * if (!ok)
- * FAIL: input was not valid base64
- * if (out == NULL)
- * FAIL: memory allocation error
- * OK: data in OUT/OUTLEN
- *
- * size_t outlen = base64_encode_alloc (in, inlen, &out);
- * if (out == NULL && outlen == 0 && inlen != 0)
- * FAIL: input too long
- * if (out == NULL)
- * FAIL: memory allocation error
- * OK: data in OUT/OUTLEN.
- *
- */
-
-/* Get prototype. */
-#include "base64.h"
-
-/* Get malloc. */
-#include <stdlib.h>
-
-/* Get UCHAR_MAX. */
-#include <limits.h>
-
-#include <string.h>
-
-/* C89 compliant way to cast 'char' to 'unsigned char'. */
-static unsigned char
-to_uchar(char ch)
-{
- return ch;
-}
-
-/* Base64 encode IN array of size INLEN into OUT array of size OUTLEN.
- If OUTLEN is less than BASE64_LENGTH(INLEN), write as many bytes as
- possible. If OUTLEN is larger than BASE64_LENGTH(INLEN), also zero
- terminate the output buffer. */
-void
-base64_encode(const char *restrict in, size_t inlen,
- char *restrict out, size_t outlen)
-{
- static const char b64str[64] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
- while (inlen && outlen) {
- *out++ = b64str[(to_uchar(in[0]) >> 2) & 0x3f];
- if (!--outlen) {
- break;
- }
- *out++ = b64str[((to_uchar(in[0]) << 4)
- + (--inlen ? to_uchar(in[1]) >> 4 : 0))
- & 0x3f];
- if (!--outlen) {
- break;
- }
- *out++ =
- (inlen
- ? b64str[((to_uchar(in[1]) << 2)
- + (--inlen ? to_uchar(in[2]) >> 6 : 0))
- & 0x3f]
- : '=');
- if (!--outlen) {
- break;
- }
- *out++ = inlen ? b64str[to_uchar(in[2]) & 0x3f] : '=';
- if (!--outlen) {
- break;
- }
- if (inlen) {
- inlen--;
- }
- if (inlen) {
- in += 3;
- }
- }
-
- if (outlen) {
- *out = '\0';
- }
-}
-
-/* Allocate a buffer and store zero terminated base64 encoded data
- from array IN of size INLEN, returning BASE64_LENGTH(INLEN), i.e.,
- the length of the encoded data, excluding the terminating zero. On
- return, the OUT variable will hold a pointer to newly allocated
- memory that must be deallocated by the caller. If output string
- length would overflow, 0 is returned and OUT is set to NULL. If
- memory allocation failed, OUT is set to NULL, and the return value
- indicates length of the requested memory block, i.e.,
- BASE64_LENGTH(inlen) + 1. */
-size_t
-base64_encode_alloc(const char *in, size_t inlen, char **out)
-{
- size_t outlen = 1 + BASE64_LENGTH(inlen);
-
- /* Check for overflow in outlen computation.
- *
- * If there is no overflow, outlen >= inlen.
- *
- * If the operation (inlen + 2) overflows then it yields at most +1, so
- * outlen is 0.
- *
- * If the multiplication overflows, we lose at least half of the
- * correct value, so the result is < ((inlen + 2) / 3) * 2, which is
- * less than (inlen + 2) * 0.66667, which is less than inlen as soon as
- * (inlen > 4).
- */
- if (inlen > outlen) {
- *out = NULL;
- return 0;
- }
-
- *out = malloc(outlen);
- if (!*out) {
- return outlen;
- }
-
- base64_encode(in, inlen, *out, outlen);
-
- return outlen - 1;
-}
-
-/* With this approach this file works independent of the charset used
- (think EBCDIC). However, it does assume that the characters in the
- Base64 alphabet (A-Za-z0-9+/) are encoded in 0..255. POSIX
- 1003.1-2001 require that char and unsigned char are 8-bit
- quantities, though, taking care of that problem. But this may be a
- potential problem on non-POSIX C99 platforms.
-
- IBM C V6 for AIX mishandles "#define B64(x) ...'x'...", so use "_"
- as the formal parameter rather than "x". */
-#define B64(_) \
- ((_) == 'A' ? 0 \
- : (_) == 'B' ? 1 \
- : (_) == 'C' ? 2 \
- : (_) == 'D' ? 3 \
- : (_) == 'E' ? 4 \
- : (_) == 'F' ? 5 \
- : (_) == 'G' ? 6 \
- : (_) == 'H' ? 7 \
- : (_) == 'I' ? 8 \
- : (_) == 'J' ? 9 \
- : (_) == 'K' ? 10 \
- : (_) == 'L' ? 11 \
- : (_) == 'M' ? 12 \
- : (_) == 'N' ? 13 \
- : (_) == 'O' ? 14 \
- : (_) == 'P' ? 15 \
- : (_) == 'Q' ? 16 \
- : (_) == 'R' ? 17 \
- : (_) == 'S' ? 18 \
- : (_) == 'T' ? 19 \
- : (_) == 'U' ? 20 \
- : (_) == 'V' ? 21 \
- : (_) == 'W' ? 22 \
- : (_) == 'X' ? 23 \
- : (_) == 'Y' ? 24 \
- : (_) == 'Z' ? 25 \
- : (_) == 'a' ? 26 \
- : (_) == 'b' ? 27 \
- : (_) == 'c' ? 28 \
- : (_) == 'd' ? 29 \
- : (_) == 'e' ? 30 \
- : (_) == 'f' ? 31 \
- : (_) == 'g' ? 32 \
- : (_) == 'h' ? 33 \
- : (_) == 'i' ? 34 \
- : (_) == 'j' ? 35 \
- : (_) == 'k' ? 36 \
- : (_) == 'l' ? 37 \
- : (_) == 'm' ? 38 \
- : (_) == 'n' ? 39 \
- : (_) == 'o' ? 40 \
- : (_) == 'p' ? 41 \
- : (_) == 'q' ? 42 \
- : (_) == 'r' ? 43 \
- : (_) == 's' ? 44 \
- : (_) == 't' ? 45 \
- : (_) == 'u' ? 46 \
- : (_) == 'v' ? 47 \
- : (_) == 'w' ? 48 \
- : (_) == 'x' ? 49 \
- : (_) == 'y' ? 50 \
- : (_) == 'z' ? 51 \
- : (_) == '0' ? 52 \
- : (_) == '1' ? 53 \
- : (_) == '2' ? 54 \
- : (_) == '3' ? 55 \
- : (_) == '4' ? 56 \
- : (_) == '5' ? 57 \
- : (_) == '6' ? 58 \
- : (_) == '7' ? 59 \
- : (_) == '8' ? 60 \
- : (_) == '9' ? 61 \
- : (_) == '+' ? 62 \
- : (_) == '/' ? 63 \
- : -1)
-
-static const signed char b64[0x100] = {
- B64(0), B64(1), B64(2), B64(3),
- B64(4), B64(5), B64(6), B64(7),
- B64(8), B64(9), B64(10), B64(11),
- B64(12), B64(13), B64(14), B64(15),
- B64(16), B64(17), B64(18), B64(19),
- B64(20), B64(21), B64(22), B64(23),
- B64(24), B64(25), B64(26), B64(27),
- B64(28), B64(29), B64(30), B64(31),
- B64(32), B64(33), B64(34), B64(35),
- B64(36), B64(37), B64(38), B64(39),
- B64(40), B64(41), B64(42), B64(43),
- B64(44), B64(45), B64(46), B64(47),
- B64(48), B64(49), B64(50), B64(51),
- B64(52), B64(53), B64(54), B64(55),
- B64(56), B64(57), B64(58), B64(59),
- B64(60), B64(61), B64(62), B64(63),
- B64(64), B64(65), B64(66), B64(67),
- B64(68), B64(69), B64(70), B64(71),
- B64(72), B64(73), B64(74), B64(75),
- B64(76), B64(77), B64(78), B64(79),
- B64(80), B64(81), B64(82), B64(83),
- B64(84), B64(85), B64(86), B64(87),
- B64(88), B64(89), B64(90), B64(91),
- B64(92), B64(93), B64(94), B64(95),
- B64(96), B64(97), B64(98), B64(99),
- B64(100), B64(101), B64(102), B64(103),
- B64(104), B64(105), B64(106), B64(107),
- B64(108), B64(109), B64(110), B64(111),
- B64(112), B64(113), B64(114), B64(115),
- B64(116), B64(117), B64(118), B64(119),
- B64(120), B64(121), B64(122), B64(123),
- B64(124), B64(125), B64(126), B64(127),
- B64(128), B64(129), B64(130), B64(131),
- B64(132), B64(133), B64(134), B64(135),
- B64(136), B64(137), B64(138), B64(139),
- B64(140), B64(141), B64(142), B64(143),
- B64(144), B64(145), B64(146), B64(147),
- B64(148), B64(149), B64(150), B64(151),
- B64(152), B64(153), B64(154), B64(155),
- B64(156), B64(157), B64(158), B64(159),
- B64(160), B64(161), B64(162), B64(163),
- B64(164), B64(165), B64(166), B64(167),
- B64(168), B64(169), B64(170), B64(171),
- B64(172), B64(173), B64(174), B64(175),
- B64(176), B64(177), B64(178), B64(179),
- B64(180), B64(181), B64(182), B64(183),
- B64(184), B64(185), B64(186), B64(187),
- B64(188), B64(189), B64(190), B64(191),
- B64(192), B64(193), B64(194), B64(195),
- B64(196), B64(197), B64(198), B64(199),
- B64(200), B64(201), B64(202), B64(203),
- B64(204), B64(205), B64(206), B64(207),
- B64(208), B64(209), B64(210), B64(211),
- B64(212), B64(213), B64(214), B64(215),
- B64(216), B64(217), B64(218), B64(219),
- B64(220), B64(221), B64(222), B64(223),
- B64(224), B64(225), B64(226), B64(227),
- B64(228), B64(229), B64(230), B64(231),
- B64(232), B64(233), B64(234), B64(235),
- B64(236), B64(237), B64(238), B64(239),
- B64(240), B64(241), B64(242), B64(243),
- B64(244), B64(245), B64(246), B64(247),
- B64(248), B64(249), B64(250), B64(251),
- B64(252), B64(253), B64(254), B64(255)
-};
-
-#if UCHAR_MAX == 255
-# define uchar_in_range(c) true
-#else
-# define uchar_in_range(c) ((c) <= 255)
-#endif
-
-/* Return true if CH is a character from the Base64 alphabet, and
- false otherwise. Note that '=' is padding and not considered to be
- part of the alphabet. */
-bool
-isbase64(char ch)
-{
- return uchar_in_range(to_uchar(ch)) && 0 <= b64[to_uchar(ch)];
-}
-
-/* Initialize decode-context buffer, CTX. */
-void
-base64_decode_ctx_init(struct base64_decode_context *ctx)
-{
- ctx->i = 0;
-}
-
-/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
- none of those four is a newline, then return *IN. Otherwise, copy up to
- 4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
- index CTX->i and setting CTX->i to reflect the number of bytes copied,
- and return CTX->buf. In either case, advance *IN to point to the byte
- after the last one processed, and set *N_NON_NEWLINE to the number of
- verified non-newline bytes accessible through the returned pointer. */
-static char *
-get_4(struct base64_decode_context *ctx,
- char const *restrict *in, char const *restrict in_end,
- size_t *n_non_newline)
-{
- if (ctx->i == 4) {
- ctx->i = 0;
- }
-
- if (ctx->i == 0) {
- char const *t = *in;
- if (4 <= in_end - *in && memchr(t, '\n', 4) == NULL) {
- /* This is the common case: no newline. */
- *in += 4;
- *n_non_newline = 4;
- return (char *)t;
- }
- }
-
- {
- /* Copy non-newline bytes into BUF. */
- char const *p = *in;
- while (p < in_end) {
- char c = *p++;
- if (c != '\n') {
- ctx->buf[ctx->i++] = c;
- if (ctx->i == 4) {
- break;
- }
- }
- }
-
- *in = p;
- *n_non_newline = ctx->i;
- return ctx->buf;
- }
-}
-
-#define return_false \
- do \
- { \
- *outp = out; \
- return false; \
- } \
- while (false)
-
-/* Decode up to four bytes of base64-encoded data, IN, of length INLEN
- into the output buffer, *OUT, of size *OUTLEN bytes. Return true if
- decoding is successful, false otherwise. If *OUTLEN is too small,
- as many bytes as possible are written to *OUT. On return, advance
- *OUT to point to the byte after the last one written, and decrement
- *OUTLEN to reflect the number of bytes remaining in *OUT. */
-static bool
-decode_4(char const *restrict in, size_t inlen,
- char *restrict *outp, size_t *outleft)
-{
- char *out = *outp;
- if (inlen < 2) {
- return false;
- }
-
- if (!isbase64(in[0]) || !isbase64(in[1])) {
- return false;
- }
-
- if (*outleft) {
- *out++ = ((b64[to_uchar(in[0])] << 2)
- | (b64[to_uchar(in[1])] >> 4));
- --*outleft;
- }
-
- if (inlen == 2) {
- return_false;
- }
-
- if (in[2] == '=') {
- if (inlen != 4) {
- return_false;
- }
-
- if (in[3] != '=') {
- return_false;
- }
- }else {
- if (!isbase64(in[2])) {
- return_false;
- }
-
- if (*outleft) {
- *out++ = (((b64[to_uchar(in[1])] << 4) & 0xf0)
- | (b64[to_uchar(in[2])] >> 2));
- --*outleft;
- }
-
- if (inlen == 3) {
- return_false;
- }
-
- if (in[3] == '=') {
- if (inlen != 4) {
- return_false;
- }
- }else {
- if (!isbase64(in[3])) {
- return_false;
- }
-
- if (*outleft) {
- *out++ = (((b64[to_uchar(in[2])] << 6) & 0xc0)
- | b64[to_uchar(in[3])]);
- --*outleft;
- }
- }
- }
-
- *outp = out;
- return true;
-}
-
-/* Decode base64-encoded input array IN of length INLEN to output array
- OUT that can hold *OUTLEN bytes. The input data may be interspersed
- with newlines. Return true if decoding was successful, i.e. if the
- input was valid base64 data, false otherwise. If *OUTLEN is too
- small, as many bytes as possible will be written to OUT. On return,
- *OUTLEN holds the length of decoded bytes in OUT. Note that as soon
- as any non-alphabet, non-newline character is encountered, decoding
- is stopped and false is returned. If INLEN is zero, then process
- only whatever data is stored in CTX.
-
- Initially, CTX must have been initialized via base64_decode_ctx_init.
- Subsequent calls to this function must reuse whatever state is recorded
- in that buffer. It is necessary for when a quadruple of base64 input
- bytes spans two input buffers.
-
- If CTX is NULL then newlines are treated as garbage and the input
- buffer is processed as a unit. */
-
-bool
-base64_decode_ctx(struct base64_decode_context *ctx,
- const char *restrict in, size_t inlen,
- char *restrict out, size_t *outlen)
-{
- size_t outleft = *outlen;
- bool ignore_newlines = ctx != NULL;
- bool flush_ctx = false;
- unsigned int ctx_i = 0;
-
- if (ignore_newlines) {
- ctx_i = ctx->i;
- flush_ctx = inlen == 0;
- }
-
-
- while (true) {
- size_t outleft_save = outleft;
- if (ctx_i == 0 && !flush_ctx) {
- while (true) {
- /* Save a copy of outleft, in case we need to re-parse this
- block of four bytes. */
- outleft_save = outleft;
- if (!decode_4(in, inlen, &out, &outleft)) {
- break;
- }
-
- in += 4;
- inlen -= 4;
- }
- }
-
- if (inlen == 0 && !flush_ctx) {
- break;
- }
-
- /* Handle the common case of 72-byte wrapped lines.
- This also handles any other multiple-of-4-byte wrapping. */
- if (inlen && *in == '\n' && ignore_newlines) {
- ++in;
- --inlen;
- continue;
- }
-
- /* Restore OUT and OUTLEFT. */
- out -= outleft_save - outleft;
- outleft = outleft_save;
-
- {
- char const *in_end = in + inlen;
- char const *non_nl;
-
- if (ignore_newlines) {
- non_nl = get_4(ctx, &in, in_end, &inlen);
- } else{
- non_nl = in; /* Might have nl in this case. */
-
- }
- /* If the input is empty or consists solely of newlines (0 non-newlines),
- then we're done. Likewise if there are fewer than 4 bytes when not
- flushing context and not treating newlines as garbage. */
- if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines)) {
- inlen = 0;
- break;
- }
- if (!decode_4(non_nl, inlen, &out, &outleft)) {
- break;
- }
-
- inlen = in_end - in;
- }
- }
-
- *outlen -= outleft;
-
- return inlen == 0;
-}
-
-/* Allocate an output buffer in *OUT, and decode the base64 encoded
- data stored in IN of size INLEN to the *OUT buffer. On return, the
- size of the decoded data is stored in *OUTLEN. OUTLEN may be NULL,
- if the caller is not interested in the decoded length. *OUT may be
- NULL to indicate an out of memory error, in which case *OUTLEN
- contains the size of the memory block needed. The function returns
- true on successful decoding and memory allocation errors. (Use the
- *OUT and *OUTLEN parameters to differentiate between successful
- decoding and memory error.) The function returns false if the
- input was invalid, in which case *OUT is NULL and *OUTLEN is
- undefined. */
-bool
-base64_decode_alloc_ctx(struct base64_decode_context *ctx,
- const char *in, size_t inlen, char **out,
- size_t *outlen)
-{
- /* This may allocate a few bytes too many, depending on input,
- but it's not worth the extra CPU time to compute the exact size.
- The exact size is 3 * (inlen + (ctx ? ctx->i : 0)) / 4, minus 1 if the
- input ends with "=" and minus another 1 if the input ends with "==".
- Dividing before multiplying avoids the possibility of overflow. */
- size_t needlen = 3 * (inlen / 4) + 3;
-
- *out = malloc(needlen);
- if (!*out) {
- return true;
- }
-
- if (!base64_decode_ctx(ctx, in, inlen, *out, &needlen)) {
- free(*out);
- *out = NULL;
- return false;
- }
-
- if (outlen) {
- *outlen = needlen;
- }
-
- return true;
-}
diff --git a/bin/base64.h b/bin/base64.h
deleted file mode 100644
index 4cc66bd..0000000
--- a/bin/base64.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* base64.h -- Encode binary data using printable characters.
- Copyright (C) 2004-2006, 2009-2012 Free Software Foundation, Inc.
- Written by Simon Josefsson.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, see <http://www.gnu.org/licenses/>. */
-
-#ifndef BASE64_H
-# define BASE64_H
-
-/* Get size_t. */
-# include <stddef.h>
-
-/* Get bool. */
-# include <stdbool.h>
-
-# ifdef __cplusplus
-extern "C" {
-# endif
-
-/* This uses that the expression (n+(k-1))/k means the smallest
- integer >= n/k, i.e., the ceiling of n/k. */
-# define BASE64_LENGTH(inlen) ((((inlen) + 2) / 3) * 4)
-
-struct base64_decode_context {
- unsigned int i;
- char buf[4];
-};
-
-extern bool isbase64(char ch);
-
-extern void base64_encode(const char *restrict in, size_t inlen,
- char *restrict out, size_t outlen);
-
-extern size_t base64_encode_alloc(const char *in, size_t inlen, char **out);
-
-extern void base64_decode_ctx_init(struct base64_decode_context *ctx);
-
-extern bool base64_decode_ctx(struct base64_decode_context *ctx,
- const char *restrict in, size_t inlen,
- char *restrict out, size_t *outlen);
-
-extern bool base64_decode_alloc_ctx(struct base64_decode_context *ctx,
- const char *in, size_t inlen,
- char **out, size_t *outlen);
-
-#define base64_decode(in, inlen, out, outlen) \
- base64_decode_ctx(NULL, in, inlen, out, outlen)
-
-#define base64_decode_alloc(in, inlen, out, outlen) \
- base64_decode_alloc_ctx(NULL, in, inlen, out, outlen)
-
-# ifdef __cplusplus
-}
-# endif
-
-#endif /* BASE64_H */
diff --git a/bin/edition_s.c b/bin/edition_s.c
new file mode 100644
index 0000000..bbc512d
--- /dev/null
+++ b/bin/edition_s.c
@@ -0,0 +1,48 @@
+
+#include "geoipupdate.h"
+#include <stdlib.h>
+#include <string.h>
+
+int edition_count(geoipupdate_s *gu) {
+ int cnt = 0;
+ for (edition_s *p = gu->license.first; p; p = p->next) {
+ cnt++;
+ }
+ return cnt;
+}
+
+void edition_delete_all(geoipupdate_s *gu) {
+ edition_s *next, *current;
+
+ for (next = gu->license.first; (current = next);) {
+ next = current->next;
+ edition_delete(current);
+ }
+}
+
+void edition_insert_once(geoipupdate_s *gu, const char *edition_id) {
+ edition_s **next = &gu->license.first;
+ for (; *next; next = &(*next)->next) {
+ if (strcmp((*next)->edition_id, edition_id) == 0) {
+ return;
+ }
+ }
+ *next = edition_new(edition_id);
+ say_if(gu->verbose, "Insert edition_id %s\n", edition_id);
+}
+
+edition_s *edition_new(const char *edition_id) {
+ edition_s *p = xmalloc(sizeof(edition_s));
+ p->edition_id = strdup(edition_id);
+ exit_if(NULL == p->edition_id,
+ "Unable to allocate memory for edition ID.\n");
+ p->next = NULL;
+ return p;
+}
+
+void edition_delete(edition_s *p) {
+ if (p) {
+ free(p->edition_id);
+ }
+ free(p);
+}
diff --git a/bin/functions.c b/bin/functions.c
index 5d0482d..8272087 100644
--- a/bin/functions.c
+++ b/bin/functions.c
@@ -9,20 +9,38 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
-static ssize_t read_file(char const * const, void * const,
- size_t const);
+static ssize_t read_file(char const *const, void *const, size_t const);
+
+// Return the length of the given string in bytes. Look at at most maxlen
+// bytes.
+//
+// This is intended to behave like strnlen(3). We don't use strnlen(3) as it is
+// not part of C99.
+size_t gu_strnlen(char const *const s, size_t const maxlen) {
+ if (!s) {
+ return 0;
+ }
+
+ char const *ptr = s;
+ size_t n = 0;
+ while (*ptr != '\0' && n < maxlen) {
+ n++;
+ ptr++;
+ }
+
+ return n;
+}
// Check whether the file looks like a valid gzip file.
//
// We open it and read in a small amount. We do this so we can check its header.
//
// Return true if it is.
-bool is_valid_gzip_file(char const * const file)
-{
+bool is_valid_gzip_file(char const *const file) {
if (file == NULL || strlen(file) == 0) {
fprintf(stderr, "is_valid_gzip_file: %s\n", strerror(EINVAL));
return false;
@@ -30,7 +48,7 @@ bool is_valid_gzip_file(char const * const file)
size_t const bufsz = 2;
- uint8_t * const buf = calloc(bufsz, sizeof(uint8_t));
+ uint8_t *const buf = calloc(bufsz, sizeof(uint8_t));
if (buf == NULL) {
fprintf(stderr, "is_valid_gzip_file: %s\n", strerror(errno));
return false;
@@ -44,8 +62,8 @@ bool is_valid_gzip_file(char const * const file)
}
if ((size_t const)sz != bufsz) {
- fprintf(stderr, "%s is not a valid gzip file (due to file size)\n",
- file);
+ fprintf(
+ stderr, "%s is not a valid gzip file (due to file size)\n", file);
free(buf);
return false;
}
@@ -72,8 +90,7 @@ bool is_valid_gzip_file(char const * const file)
// exactly 8 KiB. The useful portion may fall short of 8 KiB.
//
// The caller is responsible for the returned memory.
-char * slurp_file(char const * const file)
-{
+char *slurp_file(char const *const file) {
if (file == NULL || strlen(file) == 0) {
fprintf(stderr, "slurp_file: %s\n", strerror(EINVAL));
return NULL;
@@ -81,7 +98,7 @@ char * slurp_file(char const * const file)
size_t sz = 8193;
- char * const buf = calloc(sz, sizeof(char));
+ char *const buf = calloc(sz, sizeof(char));
if (buf == NULL) {
fprintf(stderr, "slurp_file: %s\n", strerror(errno));
return NULL;
@@ -102,9 +119,8 @@ char * slurp_file(char const * const file)
// Return how many bytes we read. -1 if there was an error.
//
// The buffer may or may not contain a string. It may be binary data.
-static ssize_t read_file(char const * const file, void * const buf,
- size_t const bufsz)
-{
+static ssize_t
+read_file(char const *const file, void *const buf, size_t const bufsz) {
if (file == NULL || strlen(file) == 0 || buf == NULL || bufsz == 0) {
fprintf(stderr, "read_file: %s\n", strerror(EINVAL));
return -1;
@@ -117,8 +133,10 @@ static ssize_t read_file(char const * const file, void * const buf,
int const fd = open(file, O_RDONLY);
if (fd == -1) {
- fprintf(stderr, "read_file: Can't open file: %s: %s\n",
- file, strerror(errno));
+ fprintf(stderr,
+ "read_file: Can't open file: %s: %s\n",
+ file,
+ strerror(errno));
return -1;
}
@@ -140,14 +158,16 @@ static ssize_t read_file(char const * const file, void * const buf,
return -1;
}
- ssize_t const read_bytes = read(fd, buf + total_read_bytes,
- bytes_left_to_read);
+ ssize_t const read_bytes =
+ read(fd, buf + total_read_bytes, bytes_left_to_read);
if (read_bytes < 0) {
if (errno == EINTR) {
retries_remaining--;
continue;
}
- fprintf(stderr, "read_file: Error reading from %s: %s\n", file,
+ fprintf(stderr,
+ "read_file: Error reading from %s: %s\n",
+ file,
strerror(errno));
close(fd);
return -1;
@@ -169,8 +189,10 @@ static ssize_t read_file(char const * const file, void * const buf,
}
if (close(fd) != 0) {
- fprintf(stderr, "read_file: Error closing file: %s: %s\n",
- file, strerror(errno));
+ fprintf(stderr,
+ "read_file: Error closing file: %s: %s\n",
+ file,
+ strerror(errno));
return -1;
}
@@ -181,15 +203,15 @@ static ssize_t read_file(char const * const file, void * const buf,
#include <assert.h>
+static void test_gu_strnlen(void);
static void test_is_valid_gzip_file(void);
static void test_slurp_file(void);
static void test_read_file(void);
-static char * get_temporary_filename(void);
-static void write_file(char const * const, void const * const,
- size_t const);
+static char *get_temporary_filename(void);
+static void write_file(char const *const, void const *const, size_t const);
-int main(void)
-{
+int main(void) {
+ test_gu_strnlen();
test_is_valid_gzip_file();
test_slurp_file();
test_read_file();
@@ -197,13 +219,68 @@ int main(void)
return 0;
}
-static void test_is_valid_gzip_file(void)
-{
- char * const filename = get_temporary_filename();
+static void test_gu_strnlen(void) {
+ struct test_case {
+ char const *const s;
+ size_t const maxlen;
+ size_t const output;
+ bool const skip_strnlen;
+ };
+
+ struct test_case const tests[] = {
+ {
+ .s = "test", .maxlen = 4, .output = 4, .skip_strnlen = false,
+ },
+ {
+ .s = "test", .maxlen = 5, .output = 4, .skip_strnlen = false,
+ },
+ {
+ .s = "test", .maxlen = 6, .output = 4, .skip_strnlen = false,
+ },
+ {
+ .s = "test", .maxlen = 14, .output = 4, .skip_strnlen = false,
+ },
+ {
+ .s = "test", .maxlen = 2, .output = 2, .skip_strnlen = false,
+ },
+ {
+ .s = "test", .maxlen = 0, .output = 0, .skip_strnlen = false,
+ },
+ {
+ .s = "", .maxlen = 4, .output = 0, .skip_strnlen = false,
+ },
+ {
+ .s = "", .maxlen = 0, .output = 0, .skip_strnlen = false,
+ },
+ {
+ .s = NULL, .maxlen = 0, .output = 0, .skip_strnlen = false,
+ },
+ {
+ .s = NULL,
+ .maxlen = 10,
+ .output = 0,
+ // segfaults strnlen
+ .skip_strnlen = true,
+ },
+ };
+
+ for (size_t i = 0; i < sizeof tests / sizeof tests[0]; i++) {
+ struct test_case const test = tests[i];
+ size_t const output = gu_strnlen(test.s, test.maxlen);
+ assert(output == test.output);
+ if (test.skip_strnlen) {
+ continue;
+ }
+ assert(output == strnlen(test.s, test.maxlen));
+ }
+}
+
+static void test_is_valid_gzip_file(void) {
+ char *const filename = get_temporary_filename();
assert(filename != NULL);
// A buffer to work with.
- uint8_t buf[4] = { 0 };
+ uint8_t buf[4] = {0};
// Test: File does not exist.
@@ -256,20 +333,19 @@ static void test_is_valid_gzip_file(void)
free(filename);
}
-static void test_slurp_file(void)
-{
- char * const filename = get_temporary_filename();
+static void test_slurp_file(void) {
+ char *const filename = get_temporary_filename();
assert(filename != NULL);
// Test: File does not exist.
- char * const contents_0 = slurp_file(filename);
+ char *const contents_0 = slurp_file(filename);
assert(contents_0 == NULL);
// Test: File is zero size.
write_file(filename, "", 0);
- char * const contents_1 = slurp_file(filename);
+ char *const contents_1 = slurp_file(filename);
assert(contents_1 != NULL);
assert(strlen(contents_1) == 0);
free(contents_1);
@@ -277,22 +353,22 @@ static void test_slurp_file(void)
// Test: File has a short string.
write_file(filename, "hello", strlen("hello"));
- char * const contents_2 = slurp_file(filename);
+ char *const contents_2 = slurp_file(filename);
assert(contents_2 != NULL);
assert(strcmp(contents_2, "hello") == 0);
free(contents_2);
// Test: File is oversize.
- char contents[8194] = { 0 };
+ char contents[8194] = {0};
memset(contents, 'a', 8193);
write_file(filename, contents, strlen(contents));
- char expected[8193] = { 0 };
+ char expected[8193] = {0};
memset(expected, 'a', 8192);
- char * const contents_3 = slurp_file(filename);
+ char *const contents_3 = slurp_file(filename);
assert(contents_3 != NULL);
assert(strcmp(contents_3, expected) == 0);
free(contents_3);
@@ -302,14 +378,13 @@ static void test_slurp_file(void)
free(filename);
}
-static void test_read_file(void)
-{
- char * const filename = get_temporary_filename();
+static void test_read_file(void) {
+ char *const filename = get_temporary_filename();
assert(filename != NULL);
// Make a buffer to work with.
size_t const bufsz = 32;
- char * const buf = calloc(bufsz, sizeof(char));
+ char *const buf = calloc(bufsz, sizeof(char));
assert(buf != NULL);
// Test: The file does not exist.
@@ -357,11 +432,10 @@ static void test_read_file(void)
free(buf);
}
-static char * get_temporary_filename(void)
-{
+static char *get_temporary_filename(void) {
size_t const sz = 64;
- char * const filename = calloc(sz, sizeof(char));
+ char *const filename = calloc(sz, sizeof(char));
assert(filename != NULL);
strcat(filename, "/tmp/test-file-XXXXXX");
@@ -374,9 +448,9 @@ static char * get_temporary_filename(void)
return filename;
}
-static void write_file(char const * const path, void const * const contents,
- size_t const sz)
-{
+static void write_file(char const *const path,
+ void const *const contents,
+ size_t const sz) {
assert(path != NULL);
assert(strlen(path) != 0);
assert(contents != NULL);
diff --git a/bin/functions.h b/bin/functions.h
index 7ee7306..d23067b 100644
--- a/bin/functions.h
+++ b/bin/functions.h
@@ -2,8 +2,10 @@
#define _GEOIPUPDATE_FUNCTIONS_H
#include <stdbool.h>
+#include <stddef.h>
-bool is_valid_gzip_file(char const * const);
-char * slurp_file(char const * const);
+size_t gu_strnlen(char const *const, size_t const);
+bool is_valid_gzip_file(char const *const);
+char *slurp_file(char const *const);
#endif
diff --git a/bin/geoipupdate-pureperl.pl b/bin/geoipupdate-pureperl.pl
index dc3e318..e68e146 100644
--- a/bin/geoipupdate-pureperl.pl
+++ b/bin/geoipupdate-pureperl.pl
@@ -86,24 +86,24 @@ open my $fh, '<', $opts{f}
or die "Error opening GeoIP Configuration file $opts{f}\n";
print "Opened License file $opts{f}\n" if $opts{v};
-my ( $user_id, $license_key, @product_ids );
+my ( $account_id, $license_key, @edition_ids );
{
local $_;
while (<$fh>) {
next if /^\s*#/; # skip comments
- /^\s*UserId\s+(\d+)/ and $user_id = $1, next;
+ /^\s*(?:AccountID|UserId)\s+(\d+)/ and $account_id = $1, next;
/^\s*LicenseKey\s+(\S{12})/ and $license_key = $1, next;
- /^\s*ProductIds(?>\s+)([A-Za-z\-_0-9 ]+)/
- and push( @product_ids, split( /\s+/, $1 ) ), next;
+ /^\s*(?:ProductIds|EditionIDs)(?>\s+)([A-Za-z\-_0-9 ]+)/
+ and push( @edition_ids, split( /\s+/, $1 ) ), next;
}
}
if ( $opts{v} ) {
- print "User id $user_id\n" if $user_id;
+ print "Account ID $account_id\n" if $account_id;
print "Read in license key $license_key\n";
- print "Product ids @product_ids\n";
+ print "Edition IDs @edition_ids\n";
}
my $err_cnt = 0;
@@ -120,15 +120,15 @@ my $print_on_error = sub {
}
};
-if ($user_id) {
- for my $product_id (@product_ids) {
+if ($account_id) {
+ for my $edition_id (@edition_ids) {
- # update the databases using the user id string,
- # the license key string and the product id for each database
+ # update the databases using the account id string,
+ # the license key string and the edition id for each database
eval {
GeoIP_update_database_general(
- $user_id, $license_key,
- $product_id, $opts{v}
+ $account_id, $license_key,
+ $edition_id, $opts{v}
);
};
$print_on_error->($@);
@@ -145,9 +145,9 @@ else {
exit( $err_cnt > 0 ? 1 : 0 );
sub GeoIP_update_database_general {
- my ( $user_id, $license_key, $product_id, $verbose, $client_ipaddr ) = @_;
+ my ( $account_id, $license_key, $edition_id, $verbose, $client_ipaddr ) = @_;
my $u = URI->new("$proto://$update_host/app/update_getfilename");
- $u->query_form( product_id => $product_id );
+ $u->query_form( product_id => $edition_id );
print 'Send request ' . $u->as_string, "\n" if ($verbose);
my $res = $ua->request( GET $u->as_string, Host => $update_host );
@@ -186,8 +186,8 @@ sub GeoIP_update_database_general {
$u->query_form(
db_md5 => shift,
challenge_md5 => $hex_digest2,
- user_id => $user_id,
- edition_id => $product_id
+ user_id => $account_id,
+ edition_id => $edition_id
);
print 'Send request ' . $u->as_string, "\n" if ($verbose);
return $ua->request( GET $u->as_string, Host => $update_host );
diff --git a/bin/geoipupdate.c b/bin/geoipupdate.c
index dc1d79b..ce347f8 100644
--- a/bin/geoipupdate.c
+++ b/bin/geoipupdate.c
@@ -1,5 +1,5 @@
-#include "functions.h"
#include "geoipupdate.h"
+#include "functions.h"
#include "md5.h"
#include <ctype.h>
@@ -13,10 +13,11 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
+#include <utime.h>
#include <zlib.h>
#define ZERO_MD5 ("00000000000000000000000000000000")
-#define say(fmt, ...) say_if(1, fmt, ## __VA_ARGS__)
+#define say(fmt, ...) say_if(1, fmt, ##__VA_ARGS__)
enum gu_status {
GU_OK = 0,
@@ -32,32 +33,32 @@ static void xasprintf(char **, const char *, ...);
static void *xcalloc(size_t, size_t);
static void *xrealloc(void *, size_t);
static void usage(void);
-static int parse_opts(geoipupdate_s *, int, char *const []);
+static int parse_opts(geoipupdate_s *, int, char *const[]);
static ssize_t my_getline(char **, size_t *, FILE *);
static int parse_license_file(geoipupdate_s *);
-static char * join_path(char const * const, char const * const);
-static int acquire_run_lock(geoipupdate_s const * const);
+static char *join_path(char const *const, char const *const);
+static int acquire_run_lock(geoipupdate_s const *const);
static int md5hex(const char *, char *);
static void common_req(CURL *, geoipupdate_s *);
-static size_t get_expected_file_md5(char *, size_t, size_t,
- char *);
-static void download_to_file(geoipupdate_s *, const char *,
- const char *, char *);
+static size_t get_expected_file_md5(char *, size_t, size_t, void *);
+static void
+download_to_file(geoipupdate_s *, const char *, const char *, char *);
+static long get_server_time(geoipupdate_s *);
static size_t mem_cb(void *, size_t, size_t, void *);
static in_mem_s *in_mem_s_new(void);
static void in_mem_s_delete(in_mem_s *);
static in_mem_s *get(geoipupdate_s *, const char *);
-static void md5hex_license_ipaddr(geoipupdate_s *, const char *,
- char *);
+static void md5hex_license_ipaddr(geoipupdate_s *, const char *, char *);
static int update_database_general_all(geoipupdate_s *);
static int update_database_general(geoipupdate_s *, const char *);
static int update_country_database(geoipupdate_s *);
-static int gunzip_and_replace(geoipupdate_s const * const,
- char const * const, char const * const,
- char const * const);
+static int gunzip_and_replace(geoipupdate_s const *const,
+ char const *const,
+ char const *const,
+ char const *const,
+ long);
-void exit_unless(int expr, const char *fmt, ...)
-{
+void exit_unless(int expr, const char *fmt, ...) {
va_list ap;
if (expr) {
return;
@@ -68,8 +69,7 @@ void exit_unless(int expr, const char *fmt, ...)
exit(1);
}
-static void xasprintf(char **ptr, const char *fmt, ...)
-{
+static void xasprintf(char **ptr, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
int rc = vasprintf(ptr, fmt, ap);
@@ -77,8 +77,7 @@ static void xasprintf(char **ptr, const char *fmt, ...)
exit_if(rc == -1, "Out of memory\n");
}
-void say_if(int expr, const char *fmt, ...)
-{
+void say_if(int expr, const char *fmt, ...) {
va_list ap;
if (!expr) {
return;
@@ -88,89 +87,87 @@ void say_if(int expr, const char *fmt, ...)
va_end(ap);
}
-static void *xcalloc(size_t nmemb, size_t size)
-{
+static void *xcalloc(size_t nmemb, size_t size) {
void *ptr = calloc(nmemb, size);
exit_if(!ptr, "Out of memory\n");
return ptr;
}
-void *xmalloc(size_t size)
-{
+void *xmalloc(size_t size) {
void *ptr = malloc(size);
exit_if(!ptr, "Out of memory\n");
return ptr;
}
-static void *xrealloc(void *ptr, size_t size)
-{
+static void *xrealloc(void *ptr, size_t size) {
void *mem = realloc(ptr, size);
exit_if(mem == NULL, "Out of memory\n");
return mem;
}
-static void usage(void)
-{
+static void usage(void) {
fprintf(
stderr,
"Usage: geoipupdate [-Vhv] [-f license_file] [-d custom directory]\n\n"
" -d DIR store downloaded files in DIR\n"
- " -f FILE use configuration found in FILE (see GeoIP.conf(5) man page)\n"
+ " -f FILE use configuration found in FILE (see GeoIP.conf(5) man "
+ "page)\n"
" -h display this help text\n"
" -v use verbose output\n"
- " -V display the version and exit\n"
- );
+ " -V display the version and exit\n");
}
-static int parse_opts(geoipupdate_s * gu, int argc, char *const argv[])
-{
+static int parse_opts(geoipupdate_s *gu, int argc, char *const argv[]) {
int c;
opterr = 0;
while ((c = getopt(argc, argv, "Vvhf:d:")) != -1) {
switch (c) {
- case 'V':
- puts(PACKAGE_STRING);
- exit(0);
- case 'v':
- gu->verbose = 1;
- break;
- case 'd':
- free(gu->database_dir);
- gu->database_dir = strdup(optarg);
- exit_if(NULL == gu->database_dir,
+ case 'V':
+ puts(PACKAGE_STRING);
+ exit(0);
+ case 'v':
+ gu->verbose = 1;
+ break;
+ case 'd':
+ free(gu->database_dir);
+ gu->database_dir = strdup(optarg);
+ exit_if(
+ NULL == gu->database_dir,
"Unable to allocate memory for database directory path.");
- // The database directory in the config file is ignored if we use -d
- gu->do_not_overwrite_database_directory = 1;
- break;
- case 'f':
- free(gu->license_file);
- gu->license_file = strdup(optarg);
- exit_if(NULL == gu->license_file,
- "Unable to allocate memory for license file path.\n");
- break;
- case 'h':
- default:
- usage();
- exit(1);
- case '?':
- if (optopt == 'f' || optopt == 'd') {
- fprintf(stderr, "Option -%c requires an argument.\n", optopt);
- } else if (isprint(optopt)) {
- fprintf(stderr, "Unknown option `-%c'.\n", optopt);
- } else{
- fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
- }
- exit(1);
+ // The database directory in the config file is ignored if we
+ // use -d
+ gu->do_not_overwrite_database_directory = 1;
+ break;
+ case 'f':
+ free(gu->license_file);
+ gu->license_file = strdup(optarg);
+ exit_if(NULL == gu->license_file,
+ "Unable to allocate memory for license file path.\n");
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(1);
+ case '?':
+ if (optopt == 'f' || optopt == 'd') {
+ fprintf(
+ stderr, "Option -%c requires an argument.\n", optopt);
+ } else if (isprint(optopt)) {
+ fprintf(stderr, "Unknown option `-%c'.\n", optopt);
+ } else {
+ fprintf(
+ stderr, "Unknown option character `\\x%x'.\n", optopt);
+ }
+ exit(1);
}
}
return GU_OK;
}
-int main(int argc, char *const argv[])
-{
+int main(int argc, char *const argv[]) {
struct stat st;
int err = GU_ERROR;
curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -179,8 +176,10 @@ int main(int argc, char *const argv[])
parse_opts(gu, argc, argv);
if (parse_license_file(gu)) {
exit_unless(stat(gu->database_dir, &st) == 0,
- "%s does not exist\n", gu->database_dir);
- exit_unless(S_ISDIR(st.st_mode), "%s is not a directory\n",
+ "%s does not exist\n",
+ gu->database_dir);
+ exit_unless(S_ISDIR(st.st_mode),
+ "%s is not a directory\n",
gu->database_dir);
// Note: access(2) checks only the real UID/GID. This is probably
// okay, but we could perform more complex checks using the stat
@@ -188,7 +187,8 @@ int main(int argc, char *const argv[])
// open the file, and avoid potential race issues where permissions
// change between now and then.
exit_unless(access(gu->database_dir, W_OK) == 0,
- "%s is not writable\n", gu->database_dir);
+ "%s is not writable\n",
+ gu->database_dir);
if (acquire_run_lock(gu) != 0) {
geoipupdate_s_delete(gu);
@@ -196,9 +196,9 @@ int main(int argc, char *const argv[])
return GU_ERROR;
}
- err = (gu->license.user_id == NO_USER_ID)
- ? update_country_database(gu)
- : update_database_general_all(gu);
+ err = (gu->license.account_id == NO_ACCOUNT_ID)
+ ? update_country_database(gu)
+ : update_database_general_all(gu);
}
geoipupdate_s_delete(gu);
}
@@ -206,21 +206,19 @@ int main(int argc, char *const argv[])
return err ? GU_ERROR : GU_OK;
}
-static ssize_t my_getline(char ** linep, size_t * linecapp, FILE * stream)
-{
+static ssize_t my_getline(char **linep, size_t *linecapp, FILE *stream) {
#if defined HAVE_GETLINE
return getline(linep, linecapp, stream);
#elif defined HAVE_FGETS
// Unbelievable, but OS X 10.6 Snow Leopard did not provide getline
- char * p = fgets(*linep, *linecapp, stream);
+ char *p = fgets(*linep, *linecapp, stream);
return p == NULL ? -1 : strlen(p);
#else
#error Your OS is not supported
#endif
}
-static int parse_license_file(geoipupdate_s * up)
-{
+static int parse_license_file(geoipupdate_s *up) {
say_if(up->verbose, "%s\n", PACKAGE_STRING);
FILE *fh = fopen(up->license_file, "rb");
exit_unless(!!fh, "Can't open license file %s\n", up->license_file);
@@ -236,32 +234,41 @@ static int parse_license_file(geoipupdate_s * up)
if (*strt == '#') {
continue;
}
- if (sscanf(strt, "UserId %d", &up->license.user_id) == 1) {
- say_if(up->verbose, "UserId %d\n", up->license.user_id);
+ if (sscanf(strt, "UserId %d", &up->license.account_id) == 1) {
+ say_if(up->verbose, "UserId %d\n", up->license.account_id);
continue;
}
- if (sscanf(strt, "LicenseKey %12s",
- &up->license.license_key[0]) == 1) {
+ if (sscanf(strt, "AccountID %d", &up->license.account_id) == 1) {
+ say_if(up->verbose, "AccountID %d\n", up->license.account_id);
+ continue;
+ }
+ if (sscanf(strt, "LicenseKey %12s", &up->license.license_key[0]) == 1) {
say_if(up->verbose, "LicenseKey %s\n", up->license.license_key);
continue;
}
char *p, *last;
if ((p = strtok_r(strt, sep, &last))) {
- if (!strcmp(p, "ProductIds")) {
+ if (!strcmp(p, "ProductIds") || !strcmp(p, "EditionIDs")) {
while ((p = strtok_r(NULL, sep, &last))) {
- product_insert_once(up, p);
+ edition_insert_once(up, p);
}
+ } else if (!strcmp(p, "PreserveFileTimes")) {
+ p = strtok_r(NULL, sep, &last);
+ exit_if(NULL == p ||
+ (0 != strcmp(p, "0") && 0 != strcmp(p, "1")),
+ "PreserveFileTimes must be 0 or 1\n");
+ up->preserve_file_times = atoi(p);
} else if (!strcmp(p, "SkipPeerVerification")) {
p = strtok_r(NULL, sep, &last);
- exit_if(NULL == p
- || (0 != strcmp(p, "0") && 0 != strcmp(p, "1")),
+ exit_if(NULL == p ||
+ (0 != strcmp(p, "0") && 0 != strcmp(p, "1")),
"SkipPeerVerification must be 0 or 1\n");
up->skip_peer_verification = atoi(p);
} else if (!strcmp(p, "Protocol")) {
p = strtok_r(NULL, sep, &last);
- exit_if(NULL == p || (0 != strcmp(p, "http")
- && 0 != strcmp(p, "https")),
+ exit_if(NULL == p ||
+ (0 != strcmp(p, "http") && 0 != strcmp(p, "https")),
"Protocol must be http or https\n");
free(up->proto);
up->proto = strdup(p);
@@ -270,7 +277,7 @@ static int parse_license_file(geoipupdate_s * up)
} else if (!strcmp(p, "SkipHostnameVerification")) {
p = strtok_r(NULL, sep, &last);
exit_if(NULL == p ||
- (0 != strcmp(p, "0") && 0 != strcmp(p, "1")),
+ (0 != strcmp(p, "0") && 0 != strcmp(p, "1")),
"SkipHostnameVerification must be 0 or 1\n");
up->skip_hostname_verification = atoi(p);
} else if (!strcmp(p, "Host")) {
@@ -283,18 +290,16 @@ static int parse_license_file(geoipupdate_s * up)
} else if (!strcmp(p, "DatabaseDirectory")) {
if (!up->do_not_overwrite_database_directory) {
p = strtok_r(NULL, sep, &last);
- exit_if(NULL == p,
- "DatabaseDirectory must be defined\n");
+ exit_if(NULL == p, "DatabaseDirectory must be defined\n");
free(up->database_dir);
up->database_dir = strdup(p);
- exit_if(
- NULL == up->database_dir,
- "Unable to allocate memory for database directory path.\n");
+ exit_if(NULL == up->database_dir,
+ "Unable to allocate memory for database directory "
+ "path.\n");
}
} else if (!strcmp(p, "Proxy")) {
p = strtok_r(NULL, sep, &last);
- exit_if(NULL == p,
- "Proxy must be defined 1.2.3.4:12345\n");
+ exit_if(NULL == p, "Proxy must be defined 1.2.3.4:12345\n");
free(up->proxy);
up->proxy = strdup(p);
exit_if(NULL == up->proxy,
@@ -309,8 +314,7 @@ static int parse_license_file(geoipupdate_s * up)
"Unable to allocate memory for proxy credentials.\n");
} else if (!strcmp(p, "LockFile")) {
p = strtok_r(NULL, sep, &last);
- exit_if(NULL == p,
- "LockFile must be a file path\n");
+ exit_if(NULL == p, "LockFile must be a file path\n");
// We could check the value looks like a path, but trying to use
// it will fail if it isn't.
free(up->lock_file);
@@ -335,8 +339,9 @@ static int parse_license_file(geoipupdate_s * up)
free(buffer);
exit_if(-1 == fclose(fh), "Error closing stream: %s", strerror(errno));
say_if(up->verbose,
- "Read in license key %s\nNumber of product ids %d\n",
- up->license_file, product_count(up));
+ "Read in license key %s\nNumber of edition IDs %d\n",
+ up->license_file,
+ edition_count(up));
return 1;
}
@@ -347,10 +352,9 @@ static int parse_license_file(geoipupdate_s * up)
//
// TODO: This function performs no validation on the given inputs beyond that
// they are present.
-static char * join_path(char const * const dir, char const * const file)
-{
+static char *join_path(char const *const dir, char const *const file) {
size_t sz = -1;
- char * path = NULL;
+ char *path = NULL;
if (dir == NULL || strlen(dir) == 0 || file == NULL || strlen(file) == 0) {
fprintf(stderr, "join_path: %s\n", strerror(EINVAL));
@@ -393,8 +397,7 @@ static char * join_path(char const * const dir, char const * const file)
// file (releasing our lock), then that other instance acquires a lock. At the
// same time, another instance runs and creates the file anew and also acquires
// a lock.
-static int acquire_run_lock(geoipupdate_s const * const gu)
-{
+static int acquire_run_lock(geoipupdate_s const *const gu) {
int fd = -1;
struct flock fl;
int i = 0;
@@ -408,7 +411,9 @@ static int acquire_run_lock(geoipupdate_s const * const gu)
fd = open(gu->lock_file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (fd == -1) {
- fprintf(stderr, "Unable to open lock file %s: %s\n", gu->lock_file,
+ fprintf(stderr,
+ "Unable to open lock file %s: %s\n",
+ gu->lock_file,
strerror(errno));
return 1;
}
@@ -428,20 +433,23 @@ static int acquire_run_lock(geoipupdate_s const * const gu)
}
// Something else went wrong. Abort.
- fprintf(stderr, "Unable to acquire lock on %s: %s\n", gu->lock_file,
+ fprintf(stderr,
+ "Unable to acquire lock on %s: %s\n",
+ gu->lock_file,
strerror(errno));
close(fd);
return 1;
}
- fprintf(stderr, "Unable to acquire lock on %s: Gave up after %d attempts\n",
- gu->lock_file, i);
+ fprintf(stderr,
+ "Unable to acquire lock on %s: Gave up after %d attempts\n",
+ gu->lock_file,
+ i);
close(fd);
return 1;
}
-static int md5hex(const char *fname, char *hex_digest)
-{
+static int md5hex(const char *fname, char *hex_digest) {
int bsize = 1024;
unsigned char buffer[bsize], digest[16];
@@ -455,8 +463,9 @@ static int md5hex(const char *fname, char *hex_digest)
}
struct stat st;
- exit_unless(stat(fname, &st) == 0
- && S_ISREG(st.st_mode), "%s is not a file\n", fname);
+ exit_unless(stat(fname, &st) == 0 && S_ISREG(st.st_mode),
+ "%s is not a file\n",
+ fname);
md5_init(&context);
while ((len = fread(buffer, 1, bsize, fh)) > 0) {
@@ -471,26 +480,32 @@ static int md5hex(const char *fname, char *hex_digest)
return 1;
}
-static void common_req(CURL * curl, geoipupdate_s * gu)
-{
+static void common_req(CURL *curl, geoipupdate_s *gu) {
curl_easy_setopt(curl, CURLOPT_USERAGENT, GEOIP_USERAGENT);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+ curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
- // CURLOPT_TCP_KEEPALIVE appeared in 7.25. It is a typedef enum, not a
- // macro so we resort to version detection.
+// CURLOPT_TCP_KEEPALIVE appeared in 7.25. It is a typedef enum, not a
+// macro so we resort to version detection.
#if LIBCURL_VERSION_NUM >= 0x071900
- curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1);
+ curl_easy_setopt(curl, CURLOPT_TCP_KEEPALIVE, 1L);
#endif
if (!strcasecmp(gu->proto, "https")) {
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,
- gu->skip_peer_verification != 0);
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST,
- gu->skip_hostname_verification != 0);
+ curl_easy_setopt(curl,
+ CURLOPT_SSL_VERIFYPEER,
+ (long)(gu->skip_peer_verification != 0));
+ curl_easy_setopt(curl,
+ CURLOPT_SSL_VERIFYHOST,
+ (long)(gu->skip_hostname_verification != 0));
+ }
+
+ if (gu->preserve_file_times) {
+ curl_easy_setopt(curl, CURLOPT_FILETIME, 1L);
}
if (gu->proxy_user_password && strlen(gu->proxy_user_password)) {
- say_if(gu->verbose, "Use proxy_user_password: %s\n",
+ say_if(gu->verbose,
+ "Use proxy_user_password: %s\n",
gu->proxy_user_password);
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, gu->proxy_user_password);
}
@@ -500,9 +515,11 @@ static void common_req(CURL * curl, geoipupdate_s * gu)
}
}
-static size_t get_expected_file_md5(char *buffer, size_t size, size_t nitems,
- char *md5)
-{
+static size_t get_expected_file_md5(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userdata) {
+ char *md5 = (char *)userdata;
size_t total_size = size * nitems;
if (strncasecmp(buffer, "X-Database-MD5:", 15) == 0 && total_size > 48) {
char *start = buffer + 16;
@@ -522,9 +539,10 @@ static size_t get_expected_file_md5(char *buffer, size_t size, size_t nitems,
// TODO(wstorey@maxmind.com): Return boolean/int whether we succeeded rather
// than exiting. Beyond being cleaner and easier to test, it will allow us to
// clean up after ourselves better.
-static void download_to_file(geoipupdate_s * gu, const char *url,
- const char *fname, char *expected_file_md5)
-{
+static void download_to_file(geoipupdate_s *gu,
+ const char *url,
+ const char *fname,
+ char *expected_file_md5) {
FILE *f = fopen(fname, "wb");
if (f == NULL) {
fprintf(stderr, "Can't open %s: %s\n", fname, strerror(errno));
@@ -547,7 +565,8 @@ static void download_to_file(geoipupdate_s * gu, const char *url,
exit_unless(res == CURLE_OK,
"curl_easy_perform() failed: %s\nConnect to %s\n",
- curl_easy_strerror(res), url);
+ curl_easy_strerror(res),
+ url);
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
@@ -564,7 +583,7 @@ static void download_to_file(geoipupdate_s * gu, const char *url,
status,
url);
// The response should contain a message containing exactly why.
- char * const message = slurp_file(fname);
+ char *const message = slurp_file(fname);
if (message) {
fprintf(stderr, "%s\n", message);
free(message);
@@ -577,7 +596,7 @@ static void download_to_file(geoipupdate_s * gu, const char *url,
// In this case, the server must have told us the current MD5 hash of the
// database we asked for.
- if (strnlen(expected_file_md5, 33) != 32) {
+ if (gu_strnlen(expected_file_md5, 33) != 32) {
fprintf(stderr,
"Did not receive a valid expected database MD5 from server\n");
unlink(fname);
@@ -585,8 +604,17 @@ static void download_to_file(geoipupdate_s * gu, const char *url,
}
}
-static size_t mem_cb(void *contents, size_t size, size_t nmemb, void *userp)
-{
+// Retrieve the server file time for the previous HTTP request.
+static long get_server_time(geoipupdate_s *gu) {
+ CURL *curl = gu->curl;
+ long filetime = -1;
+ if (curl != NULL) {
+ curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
+ }
+ return filetime;
+}
+
+static size_t mem_cb(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
if (realsize == 0) {
@@ -603,24 +631,21 @@ static size_t mem_cb(void *contents, size_t size, size_t nmemb, void *userp)
return realsize;
}
-static in_mem_s *in_mem_s_new(void)
-{
+static in_mem_s *in_mem_s_new(void) {
in_mem_s *mem = (in_mem_s *)xmalloc(sizeof(in_mem_s));
mem->ptr = (char *)xcalloc(1, 1);
mem->size = 0;
return mem;
}
-static void in_mem_s_delete(in_mem_s * mem)
-{
+static void in_mem_s_delete(in_mem_s *mem) {
if (mem) {
free(mem->ptr);
free(mem);
}
}
-static in_mem_s *get(geoipupdate_s * gu, const char *url)
-{
+static in_mem_s *get(geoipupdate_s *gu, const char *url) {
in_mem_s *mem = in_mem_s_new();
say_if(gu->verbose, "url: %s\n", url);
@@ -632,14 +657,16 @@ static in_mem_s *get(geoipupdate_s * gu, const char *url)
CURLcode res = curl_easy_perform(curl);
exit_unless(res == CURLE_OK,
"curl_easy_perform() failed: %s\nConnect to %s\n",
- curl_easy_strerror(res), url);
+ curl_easy_strerror(res),
+ url);
long status = 0;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
- exit_if( status < 200 || status >= 300,
- "Received an unexpected HTTP status code of %ld from %s",
- status, url);
+ exit_if(status < 200 || status >= 300,
+ "Received an unexpected HTTP status code of %ld from %s",
+ status,
+ url);
return mem;
}
@@ -648,13 +675,14 @@ static in_mem_s *get(geoipupdate_s * gu, const char *url)
//
// This hash is suitable for the challenge parameter for downloading from the
// /update_secure endpoint.
-static void md5hex_license_ipaddr(geoipupdate_s * gu, const char *client_ipaddr,
- char *new_digest_str)
-{
+static void md5hex_license_ipaddr(geoipupdate_s *gu,
+ const char *client_ipaddr,
+ char *new_digest_str) {
unsigned char digest[16];
MD5_CONTEXT context;
md5_init(&context);
- md5_write(&context, (unsigned char *)gu->license.license_key,
+ md5_write(&context,
+ (unsigned char *)gu->license.license_key,
strlen(gu->license.license_key));
md5_write(&context, (unsigned char *)client_ipaddr, strlen(client_ipaddr));
md5_final(&context);
@@ -664,19 +692,21 @@ static void md5hex_license_ipaddr(geoipupdate_s * gu, const char *client_ipaddr,
}
}
-static int update_database_general(geoipupdate_s * gu, const char *product_id)
-{
+static int update_database_general(geoipupdate_s *gu, const char *edition_id) {
char *url = NULL, *geoip_filename = NULL, *geoip_gz_filename = NULL,
- *client_ipaddr = NULL;
- char hex_digest[33] = { 0 }, hex_digest2[33] = { 0 };
+ *client_ipaddr = NULL;
+ char hex_digest[33] = {0}, hex_digest2[33] = {0};
// Get the filename.
- xasprintf(&url, "%s://%s/app/update_getfilename?product_id=%s",
- gu->proto, gu->host, product_id);
+ xasprintf(&url,
+ "%s://%s/app/update_getfilename?product_id=%s",
+ gu->proto,
+ gu->host,
+ edition_id);
in_mem_s *mem = get(gu, url);
free(url);
if (mem->size == 0) {
- fprintf(stderr, "product_id %s not found\n", product_id);
+ fprintf(stderr, "edition_id %s not found\n", edition_id);
in_mem_s_delete(mem);
return GU_ERROR;
}
@@ -712,14 +742,19 @@ static int update_database_general(geoipupdate_s * gu, const char *product_id)
say_if(gu->verbose, "md5hex_digest2 (challenge): %s\n", hex_digest2);
// Download.
- xasprintf(
- &url,
- "%s://%s/app/update_secure?db_md5=%s&challenge_md5=%s&user_id=%d&edition_id=%s",
- gu->proto, gu->host, hex_digest, hex_digest2,
- gu->license.user_id, product_id);
+ xasprintf(&url,
+ "%s://%s/app/"
+ "update_secure?db_md5=%s&challenge_md5=%s&user_id=%d&edition_id=%"
+ "s",
+ gu->proto,
+ gu->host,
+ hex_digest,
+ hex_digest2,
+ gu->license.account_id,
+ edition_id);
xasprintf(&geoip_gz_filename, "%s.gz", geoip_filename);
- char expected_file_md5[33] = { 0 };
+ char expected_file_md5[33] = {0};
download_to_file(gu, url, geoip_gz_filename, expected_file_md5);
free(url);
@@ -734,8 +769,12 @@ static int update_database_general(geoipupdate_s * gu, const char *product_id)
return GU_OK;
}
- int rc = gunzip_and_replace(gu, geoip_gz_filename, geoip_filename,
- expected_file_md5);
+ long filetime = -1;
+ if (gu->preserve_file_times) {
+ filetime = get_server_time(gu);
+ }
+ int rc = gunzip_and_replace(
+ gu, geoip_gz_filename, geoip_filename, expected_file_md5, filetime);
free(geoip_gz_filename);
free(geoip_filename);
@@ -743,20 +782,17 @@ static int update_database_general(geoipupdate_s * gu, const char *product_id)
return rc;
}
-static int update_database_general_all(geoipupdate_s * gu)
-{
+static int update_database_general_all(geoipupdate_s *gu) {
int err = 0;
- for (product_s ** next = &gu->license.first; *next; next =
- &(*next)->next) {
- err |= update_database_general(gu, (*next)->product_id);
+ for (edition_s **next = &gu->license.first; *next; next = &(*next)->next) {
+ err |= update_database_general(gu, (*next)->edition_id);
}
return err;
}
-static int update_country_database(geoipupdate_s * gu)
-{
+static int update_country_database(geoipupdate_s *gu) {
char *geoip_filename = NULL, *geoip_gz_filename = NULL, *url = NULL;
- char hex_digest[33] = { 0 };
+ char hex_digest[33] = {0};
xasprintf(&geoip_filename, "%s/GeoIP.dat", gu->database_dir);
xasprintf(&geoip_gz_filename, "%s/GeoIP.dat.gz", gu->database_dir);
@@ -768,9 +804,12 @@ static int update_country_database(geoipupdate_s * gu)
xasprintf(&url,
"%s://%s/app/update?license_key=%s&md5=%s",
- gu->proto, gu->host, &gu->license.license_key[0], hex_digest);
+ gu->proto,
+ gu->host,
+ &gu->license.license_key[0],
+ hex_digest);
- char expected_file_md5[33] = { 0 };
+ char expected_file_md5[33] = {0};
download_to_file(gu, url, geoip_gz_filename, expected_file_md5);
free(url);
@@ -785,8 +824,12 @@ static int update_country_database(geoipupdate_s * gu)
return GU_OK;
}
- int rc = gunzip_and_replace(gu, geoip_gz_filename, geoip_filename,
- expected_file_md5);
+ long filetime = -1;
+ if (gu->preserve_file_times) {
+ filetime = get_server_time(gu);
+ }
+ int rc = gunzip_and_replace(
+ gu, geoip_gz_filename, geoip_filename, expected_file_md5, filetime);
free(geoip_gz_filename);
free(geoip_filename);
@@ -806,16 +849,16 @@ static int update_country_database(geoipupdate_s * gu)
//
// We also remove the gzip file once we successfully decompress and move the
// new database into place.
-static int gunzip_and_replace(geoipupdate_s const * const gu,
- char const * const gzipfile,
- char const * const geoip_filename,
- char const * const expected_file_md5)
-{
- if (gu == NULL ||
- gu->database_dir == NULL || strlen(gu->database_dir) == 0 ||
- gzipfile == NULL || strlen(gzipfile) == 0 ||
- geoip_filename == NULL || strlen(geoip_filename) == 0 ||
- expected_file_md5 == NULL || strlen(expected_file_md5) == 0) {
+static int gunzip_and_replace(geoipupdate_s const *const gu,
+ char const *const gzipfile,
+ char const *const geoip_filename,
+ char const *const expected_file_md5,
+ long filetime) {
+ if (gu == NULL || gu->database_dir == NULL ||
+ strlen(gu->database_dir) == 0 || gzipfile == NULL ||
+ strlen(gzipfile) == 0 || geoip_filename == NULL ||
+ strlen(geoip_filename) == 0 || expected_file_md5 == NULL ||
+ strlen(expected_file_md5) == 0) {
fprintf(stderr, "gunzip_and_replace: %s\n", strerror(EINVAL));
return GU_ERROR;
}
@@ -838,7 +881,7 @@ static int gunzip_and_replace(geoipupdate_s const * const gu,
exit_if(fhw == NULL, "Can't open %s\n", file_path_test);
size_t const bsize = 8192;
- char * const buffer = calloc(bsize, sizeof(char));
+ char *const buffer = calloc(bsize, sizeof(char));
if (!buffer) {
fprintf(stderr, "gunzip_and_replace: %s\n", strerror(errno));
free(file_path_test);
@@ -847,7 +890,7 @@ static int gunzip_and_replace(geoipupdate_s const * const gu,
return GU_ERROR;
}
- for (;; ) {
+ for (;;) {
int amt = gzread(gz_fh, buffer, bsize);
if (amt == 0) {
// EOF
@@ -858,29 +901,46 @@ static int gunzip_and_replace(geoipupdate_s const * const gu,
"Gzip write error\n");
}
exit_if(-1 == fclose(fhw), "Error closing stream: %s", strerror(errno));
- exit_if(gzclose(gz_fh) != Z_OK, "Gzip read error while closing from %s\n",
+ exit_if(gzclose(gz_fh) != Z_OK,
+ "Gzip read error while closing from %s\n",
gzipfile);
free(buffer);
- char actual_md5[33] = { 0 };
+ char actual_md5[33] = {0};
md5hex(file_path_test, actual_md5);
exit_if(strncasecmp(actual_md5, expected_file_md5, 32),
"MD5 of new database (%s) does not match expected MD5 (%s)",
- actual_md5, expected_file_md5);
+ actual_md5,
+ expected_file_md5);
say_if(gu->verbose, "Rename %s to %s\n", file_path_test, geoip_filename);
int err = rename(file_path_test, geoip_filename);
exit_if(err, "Rename %s to %s failed\n", file_path_test, geoip_filename);
+ if (gu->preserve_file_times && filetime > 0) {
+ struct utimbuf utb;
+ utb.modtime = utb.actime = (time_t)filetime;
+ err = utime(geoip_filename, &utb);
+ exit_if(err,
+ "Setting timestamp of %s to %ld failed: %s\n",
+ geoip_filename,
+ filetime,
+ strerror(errno));
+ }
+
// fsync directory to ensure the rename is durable
int dirfd = open(gu->database_dir, O_DIRECTORY);
- exit_if(-1 == dirfd, "Error opening database directory: %s",
- strerror(errno));
- exit_if(-1 == fsync(dirfd), "Error syncing database directory: %s",
+ exit_if(
+ -1 == dirfd, "Error opening database directory: %s", strerror(errno));
+ exit_if(-1 == fsync(dirfd),
+ "Error syncing database directory: %s",
strerror(errno));
- exit_if(-1 == close(dirfd), "Error closing database directory: %s",
+ exit_if(-1 == close(dirfd),
+ "Error closing database directory: %s",
strerror(errno));
- exit_if(-1 == unlink(gzipfile), "Error unlinking %s: %s", gzipfile,
+ exit_if(-1 == unlink(gzipfile),
+ "Error unlinking %s: %s",
+ gzipfile,
strerror(errno));
free(file_path_test);
diff --git a/bin/geoipupdate.h b/bin/geoipupdate.h
index 2241c5f..1f670e0 100644
--- a/bin/geoipupdate.h
+++ b/bin/geoipupdate.h
@@ -1,19 +1,19 @@
#ifndef GEOIPUPDATE_H
-# define GEOIPUPDATE_H (1)
+#define GEOIPUPDATE_H (1)
-#include <stdlib.h>
#include <curl/curl.h>
+#include <stdlib.h>
-typedef struct product_s {
- char *product_id;
- struct product_s *next;
-} product_s;
+typedef struct edition_s {
+ char *edition_id;
+ struct edition_s *next;
+} edition_s;
typedef struct {
- int user_id;
+ int account_id;
char license_key[13];
- product_s *first;
+ edition_s *first;
} license_s;
typedef struct {
@@ -22,35 +22,36 @@ typedef struct {
// user might change these before geoipupdate_s_init
int skip_peer_verification;
int skip_hostname_verification;
+ int preserve_file_times;
int do_not_overwrite_database_directory;
- char * license_file;
- char * database_dir;
- char * host;
- char * proto;
- char * proxy; // 1.2.3.4, 1.2.3.4:1234
- char * proxy_user_password; // user:pwd
- char * lock_file; // Path to a global runtime lock file.
+ char *license_file;
+ char *database_dir;
+ char *host;
+ char *proto;
+ char *proxy; // 1.2.3.4, 1.2.3.4:1234
+ char *proxy_user_password; // user:pwd
+ char *lock_file; // Path to a global runtime lock file.
int verbose;
- CURL * curl;
+ CURL *curl;
} geoipupdate_s;
-geoipupdate_s * geoipupdate_s_new(void);
-void geoipupdate_s_delete(geoipupdate_s * gu);
-void product_delete_all(geoipupdate_s * gu);
+geoipupdate_s *geoipupdate_s_new(void);
+void geoipupdate_s_delete(geoipupdate_s *gu);
+void edition_delete_all(geoipupdate_s *gu);
-int product_count(geoipupdate_s * gu);
-void product_insert_once(geoipupdate_s * gu, const char *product_id);
-product_s *product_new(const char *product_id);
-void product_delete(product_s * p);
+int edition_count(geoipupdate_s *gu);
+void edition_insert_once(geoipupdate_s *gu, const char *edition_id);
+edition_s *edition_new(const char *edition_id);
+void edition_delete(edition_s *p);
void exit_unless(int expr, const char *fmt, ...);
void say_if(int expr, const char *fmt, ...);
void *xmalloc(size_t size);
-# define NO_USER_ID (-1)
-# define GEOIP_USERAGENT "geoipupdate/" VERSION
+#define NO_ACCOUNT_ID (-1)
+#define GEOIP_USERAGENT "geoipupdate/" VERSION
-#define exit_if(expr, ...) exit_unless(!(expr), ## __VA_ARGS__)
+#define exit_if(expr, ...) exit_unless(!(expr), ##__VA_ARGS__)
#endif
diff --git a/bin/geoipupdate_s.c b/bin/geoipupdate_s.c
index 095e8f5..367427f 100644
--- a/bin/geoipupdate_s.c
+++ b/bin/geoipupdate_s.c
@@ -1,10 +1,9 @@
#include "geoipupdate.h"
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
-geoipupdate_s *geoipupdate_s_new(void)
-{
+geoipupdate_s *geoipupdate_s_new(void) {
size_t size = sizeof(geoipupdate_s);
geoipupdate_s *gu = xmalloc(size);
memset(gu, 0, size);
@@ -22,12 +21,10 @@ geoipupdate_s *geoipupdate_s_new(void)
"Unable to allocate memory for request protocol.\n");
gu->host = strdup("updates.maxmind.com");
- exit_if(NULL == gu->host,
- "Unable to allocate memory for update host.\n");
+ exit_if(NULL == gu->host, "Unable to allocate memory for update host.\n");
gu->proxy = strdup("");
- exit_if(NULL == gu->proxy,
- "Unable to allocate memory for proxy host.\n");
+ exit_if(NULL == gu->proxy, "Unable to allocate memory for proxy host.\n");
gu->proxy_user_password = strdup("");
exit_if(NULL == gu->proxy_user_password,
@@ -38,20 +35,18 @@ geoipupdate_s *geoipupdate_s_new(void)
"Unable to allocate memory for lock file path.\n");
gu->verbose = 0;
- gu->license.user_id = NO_USER_ID;
+ gu->license.account_id = NO_ACCOUNT_ID;
gu->license.license_key[12] = 0;
gu->curl = curl_easy_init();
- exit_if(NULL == gu->curl,
- "Unable to initialize curl.\n");
+ exit_if(NULL == gu->curl, "Unable to initialize curl.\n");
return gu;
}
-void geoipupdate_s_delete(geoipupdate_s * gu)
-{
+void geoipupdate_s_delete(geoipupdate_s *gu) {
if (gu) {
- product_delete_all(gu);
+ edition_delete_all(gu);
free(gu->license_file);
free(gu->database_dir);
free(gu->proto);
@@ -65,4 +60,3 @@ void geoipupdate_s_delete(geoipupdate_s * gu)
free(gu);
}
}
-
diff --git a/bin/md5.c b/bin/md5.c
index 6b9c74d..66a734f 100644
--- a/bin/md5.c
+++ b/bin/md5.c
@@ -22,10 +22,10 @@
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
/* Heavily modified for GnuPG by <wk@gnupg.org> */
+#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <assert.h>
#include "types.h"
@@ -34,15 +34,18 @@
#endif
//#define DIM(v) (sizeof(v)/sizeof((v)[0]))
-#define wipememory2(_ptr, _set, _len) \
- do { volatile char *_vptr = \
- (volatile char *)(_ptr); \
- size_t _vlen = (_len); \
- while (_vlen) { *_vptr = (_set); \
- _vptr++; _vlen--; \
- } } while (0)
+#define wipememory2(_ptr, _set, _len) \
+ do { \
+ volatile char *_vptr = (volatile char *)(_ptr); \
+ size_t _vlen = (_len); \
+ while (_vlen) { \
+ *_vptr = (_set); \
+ _vptr++; \
+ _vlen--; \
+ } \
+ } while (0)
#define wipememory(_ptr, _len) wipememory2(_ptr, 0, _len)
-#define rol(x, n) ( ((x) << (n)) | ((x) >> (32 - (n))) )
+#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
typedef struct {
u32 A, B, C, D; /* chaining variables */
@@ -51,10 +54,7 @@ typedef struct {
int count;
} MD5_CONTEXT;
-
-void
-md5_init( MD5_CONTEXT *ctx )
-{
+void md5_init(MD5_CONTEXT *ctx) {
ctx->A = 0x67452301;
ctx->B = 0xefcdab89;
ctx->C = 0x98badcfe;
@@ -64,9 +64,6 @@ md5_init( MD5_CONTEXT *ctx )
ctx->count = 0;
}
-
-
-
/* These are the four functions used in the four steps of the MD5 algorithm
and defined in the RFC 1321. The first function is a little bit optimized
(as found in Colin Plumbs public domain implementation). */
@@ -76,9 +73,7 @@ md5_init( MD5_CONTEXT *ctx )
#define FH(b, c, d) (b ^ c ^ d)
#define FI(b, c, d) (c ^ (b | ~d))
-static void
-burn_stack(int bytes)
-{
+static void burn_stack(int bytes) {
char buf[128];
wipememory(buf, sizeof buf);
@@ -88,15 +83,12 @@ burn_stack(int bytes)
}
}
-
-
/****************
* transform n*64 bytes
*/
static void
-/*transform( MD5_CONTEXT *ctx, const void *buffer, size_t len )*/
-transform( MD5_CONTEXT *ctx, byte *data )
-{
+ /*transform( MD5_CONTEXT *ctx, const void *buffer, size_t len )*/
+ transform(MD5_CONTEXT *ctx, byte *data) {
u32 correct_words[16];
u32 A = ctx->A;
u32 B = ctx->B;
@@ -105,29 +97,27 @@ transform( MD5_CONTEXT *ctx, byte *data )
u32 *cwp = correct_words;
#ifdef BIG_ENDIAN_HOST
- { int i;
- byte *p2, *p1;
- for (i = 0, p1 = data, p2 = (byte *)correct_words; i < 16; i++, p2 +=
- 4) {
- p2[3] = *p1++;
- p2[2] = *p1++;
- p2[1] = *p1++;
- p2[0] = *p1++;
- }
+ {
+ int i;
+ byte *p2, *p1;
+ for (i = 0, p1 = data, p2 = (byte *)correct_words; i < 16;
+ i++, p2 += 4) {
+ p2[3] = *p1++;
+ p2[2] = *p1++;
+ p2[1] = *p1++;
+ p2[0] = *p1++;
+ }
}
#else
- memcpy( correct_words, data, 64 );
+ memcpy(correct_words, data, 64);
#endif
-
-#define OP(a, b, c, d, s, T) \
- do \
- { \
- a += FF(b, c, d) + (*cwp++) + T; \
- a = rol(a, s); \
- a += b; \
- } \
- while (0)
+#define OP(a, b, c, d, s, T) \
+ do { \
+ a += FF(b, c, d) + (*cwp++) + T; \
+ a = rol(a, s); \
+ a += b; \
+ } while (0)
/* Before we start, one word about the strange constants.
They are defined in RFC 1321 as
@@ -154,14 +144,12 @@ transform( MD5_CONTEXT *ctx, byte *data )
OP(B, C, D, A, 22, 0x49b40821);
#undef OP
-#define OP(f, a, b, c, d, k, s, T) \
- do \
- { \
- a += f(b, c, d) + correct_words[k] + T; \
- a = rol(a, s); \
- a += b; \
- } \
- while (0)
+#define OP(f, a, b, c, d, k, s, T) \
+ do { \
+ a += f(b, c, d) + correct_words[k] + T; \
+ a = rol(a, s); \
+ a += b; \
+ } while (0)
/* Round 2. */
OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
@@ -224,17 +212,13 @@ transform( MD5_CONTEXT *ctx, byte *data )
ctx->D += D;
}
-
-
/* The routine updates the message-digest context to
* account for the presence of each of the characters inBuf[0..inLen-1]
* in the message whose digest is being computed.
*/
-void
-md5_write( MD5_CONTEXT *hd, byte *inbuf, size_t inlen)
-{
+void md5_write(MD5_CONTEXT *hd, byte *inbuf, size_t inlen) {
if (hd->count == 64) { /* flush the buffer */
- transform( hd, hd->buf );
+ transform(hd, hd->buf);
burn_stack(80 + 6 * sizeof(void *));
hd->count = 0;
hd->nblocks++;
@@ -246,14 +230,14 @@ md5_write( MD5_CONTEXT *hd, byte *inbuf, size_t inlen)
for (; inlen && hd->count < 64; inlen--) {
hd->buf[hd->count++] = *inbuf++;
}
- md5_write( hd, NULL, 0 );
+ md5_write(hd, NULL, 0);
if (!inlen) {
return;
}
}
while (inlen >= 64) {
- transform( hd, inbuf );
+ transform(hd, inbuf);
hd->count = 0;
hd->nblocks++;
inlen -= 64;
@@ -270,13 +254,12 @@ md5_write( MD5_CONTEXT *hd, byte *inbuf, size_t inlen)
* Returns 16 bytes representing the digest.
*/
-void
-md5_final( MD5_CONTEXT *hd )
-{
+void md5_final(MD5_CONTEXT *hd) {
u32 t, msb, lsb;
byte *p;
- md5_write(hd, NULL, 0); /* flush */;
+ md5_write(hd, NULL, 0); /* flush */
+ ;
t = hd->nblocks;
/* multiply by 64 to make a byte count */
@@ -284,7 +267,7 @@ md5_final( MD5_CONTEXT *hd )
msb = t >> 26;
/* add the count */
t = lsb;
- if ( (lsb += hd->count) < t) {
+ if ((lsb += hd->count) < t) {
msb++;
}
/* multiply by 8 to make a bit count */
@@ -293,18 +276,19 @@ md5_final( MD5_CONTEXT *hd )
msb <<= 3;
msb |= t >> 29;
- if (hd->count < 56) { /* enough room */
- hd->buf[hd->count++] = 0x80; /* pad */
+ if (hd->count < 56) { /* enough room */
+ hd->buf[hd->count++] = 0x80; /* pad */
while (hd->count < 56) {
hd->buf[hd->count++] = 0; /* pad */
}
- }else { /* need one extra block */
- hd->buf[hd->count++] = 0x80; /* pad character */
+ } else { /* need one extra block */
+ hd->buf[hd->count++] = 0x80; /* pad character */
while (hd->count < 64) {
hd->buf[hd->count++] = 0;
}
- md5_write(hd, NULL, 0); /* flush */;
- memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
+ md5_write(hd, NULL, 0); /* flush */
+ ;
+ memset(hd->buf, 0, 56); /* fill next block with zeroes */
}
/* append the 64 bit count */
hd->buf[56] = lsb;
@@ -315,21 +299,28 @@ md5_final( MD5_CONTEXT *hd )
hd->buf[61] = msb >> 8;
hd->buf[62] = msb >> 16;
hd->buf[63] = msb >> 24;
- transform( hd, hd->buf );
+ transform(hd, hd->buf);
burn_stack(80 + 6 * sizeof(void *));
p = hd->buf;
#ifdef BIG_ENDIAN_HOST
-#define X(a) \
- do { *p++ = hd->a; *p++ = hd->a >> 8; \
- *p++ = hd->a >> 16; *p++ = hd->a >> 24; } while (0)
+#define X(a) \
+ do { \
+ *p++ = hd->a; \
+ *p++ = hd->a >> 8; \
+ *p++ = hd->a >> 16; \
+ *p++ = hd->a >> 24; \
+ } while (0)
#else /* little endian */
-#define X(a) do { *(u32 *)p = hd->a; p += 4; } while (0)
+#define X(a) \
+ do { \
+ *(u32 *)p = hd->a; \
+ p += 4; \
+ } while (0)
#endif
X(A);
X(B);
X(C);
X(D);
#undef X
-
}
diff --git a/bin/md5.h b/bin/md5.h
index f949cca..1a81083 100644
--- a/bin/md5.h
+++ b/bin/md5.h
@@ -28,13 +28,12 @@
#include "types.h"
typedef struct {
- u32 A, B, C, D; /* chaining variables */
+ u32 A, B, C, D; /* chaining variables */
u32 nblocks;
byte buf[64];
int count;
} MD5_CONTEXT;
-void md5_init( MD5_CONTEXT *ctx );
-void md5_write( MD5_CONTEXT *hd, byte *inbuf, size_t inlen);
-void md5_final( MD5_CONTEXT *hd );
-
+void md5_init(MD5_CONTEXT *ctx);
+void md5_write(MD5_CONTEXT *hd, byte *inbuf, size_t inlen);
+void md5_final(MD5_CONTEXT *hd);
diff --git a/bin/product_s.c b/bin/product_s.c
deleted file mode 100644
index d4a95b3..0000000
--- a/bin/product_s.c
+++ /dev/null
@@ -1,54 +0,0 @@
-
-#include "geoipupdate.h"
-#include <string.h>
-#include <stdlib.h>
-
-int product_count(geoipupdate_s * gu)
-{
- int cnt = 0;
- for (product_s * p = gu->license.first; p; p = p->next) {
- cnt++;
- }
- return cnt;
-}
-
-void product_delete_all(geoipupdate_s * gu)
-{
- product_s *next, *current;
-
- for (next = gu->license.first; (current = next); ) {
- next = current->next;
- product_delete(current);
- }
-}
-
-void product_insert_once(geoipupdate_s * gu, const char *product_id)
-{
- product_s **next = &gu->license.first;
- for (; *next; next = &(*next)->next) {
- if (strcmp((*next)->product_id, product_id) == 0) {
- return;
- }
- }
- *next = product_new(product_id);
- say_if(gu->verbose, "Insert product_id %s\n", product_id);
-
-}
-
-product_s *product_new(const char *product_id)
-{
- product_s *p = xmalloc(sizeof(product_s));
- p->product_id = strdup(product_id);
- exit_if(NULL == p->product_id,
- "Unable to allocate memory for product ID.\n");
- p->next = NULL;
- return p;
-}
-
-void product_delete(product_s * p)
-{
- if (p) {
- free(p->product_id);
- }
- free(p);
-}
diff --git a/bin/types.h b/bin/types.h
index 9e3e5cc..dfda3a5 100644
--- a/bin/types.h
+++ b/bin/types.h
@@ -41,11 +41,10 @@
#define SIZEOF_UNSIGNED_LONG 4
#endif
-
#include <sys/types.h>
#ifndef HAVE_BYTE_TYPEDEF
-#undef byte /* maybe there is a macro with this name */
+#undef byte /* maybe there is a macro with this name */
#ifndef __riscos__
typedef unsigned char byte;
#else
@@ -58,19 +57,19 @@ typedef char byte;
#endif
#ifndef HAVE_USHORT_TYPEDEF
-#undef ushort /* maybe there is a macro with this name */
+#undef ushort /* maybe there is a macro with this name */
typedef unsigned short ushort;
#define HAVE_USHORT_TYPEDEF
#endif
#ifndef HAVE_ULONG_TYPEDEF
-#undef ulong /* maybe there is a macro with this name */
+#undef ulong /* maybe there is a macro with this name */
typedef unsigned long ulong;
#define HAVE_ULONG_TYPEDEF
#endif
#ifndef HAVE_U16_TYPEDEF
-#undef u16 /* maybe there is a macro with this name */
+#undef u16 /* maybe there is a macro with this name */
#if SIZEOF_UNSIGNED_INT == 2
typedef unsigned int u16;
#elif SIZEOF_UNSIGNED_SHORT == 2
@@ -82,7 +81,7 @@ typedef unsigned short u16;
#endif
#ifndef HAVE_U32_TYPEDEF
-#undef u32 /* maybe there is a macro with this name */
+#undef u32 /* maybe there is a macro with this name */
#if SIZEOF_UNSIGNED_INT == 4
typedef unsigned int u32;
#elif SIZEOF_UNSIGNED_LONG == 4
@@ -99,22 +98,22 @@ typedef unsigned long u32;
* Solaris and IRIX.
*/
#ifndef HAVE_U64_TYPEDEF
-#undef u64 /* maybe there is a macro with this name */
+#undef u64 /* maybe there is a macro with this name */
#if SIZEOF_UINT64_T == 8
typedef uint64_t u64;
#define U64_C(c) (UINT64_C(c))
#define HAVE_U64_TYPEDEF
#elif SIZEOF_UNSIGNED_INT == 8
typedef unsigned int u64;
-#define U64_C(c) (c ## U)
+#define U64_C(c) (c##U)
#define HAVE_U64_TYPEDEF
#elif SIZEOF_UNSIGNED_LONG == 8
typedef unsigned long u64;
-#define U64_C(c) (c ## UL)
+#define U64_C(c) (c##UL)
#define HAVE_U64_TYPEDEF
#elif SIZEOF_UNSIGNED_LONG_LONG == 8
typedef unsigned long long u64;
-#define U64_C(c) (c ## ULL)
+#define U64_C(c) (c##ULL)
#define HAVE_U64_TYPEDEF
#endif
#endif
@@ -135,6 +134,6 @@ typedef struct string_list {
struct string_list *next;
unsigned int flags;
char d[1];
-} *STRLIST;
+} * STRLIST;
#endif /*G10_TYPES_H*/
diff --git a/conf/GeoIP.conf.default b/conf/GeoIP.conf.default
index d3caf4f..b165671 100644
--- a/conf/GeoIP.conf.default
+++ b/conf/GeoIP.conf.default
@@ -2,19 +2,15 @@
# on setting up geoipupdate, including information on how to download a
# pre-filled GeoIP.conf file.
-# Enter your user ID and license key below. These are available from
+# Enter your account ID and license key below. These are available from
# https://www.maxmind.com/en/my_license_key. If you are only using free
-# GeoLite databases, you make leave the 0 values.
-UserId 0
+# GeoLite databases, you may leave the 0 values.
+AccountID 0
LicenseKey 000000000000
-# Enter the product IDs of the databases you would like to update.
-# Multiple product IDs are separated by spaces.
-ProductIds GeoLite2-Country GeoLite2-City
-
-# The following are for the GeoLite Legacy databases. To update them,
-# uncomment.
-# ProductIds 506 517 533 GeoLite-Legacy-IPv6-Country GeoLite-Legacy-IPv6-City
+# Enter the edition IDs of the databases you would like to update.
+# Multiple edition IDs are separated by spaces.
+EditionIDs GeoLite2-Country GeoLite2-City
# The remaining settings are OPTIONAL.
@@ -43,6 +39,10 @@ ProductIds GeoLite2-Country GeoLite2-City
# Defaults to "0".
# SkipPeerVerification 0
+# Whether to preserve modification times of files downloaded from the server.
+# Defaults to "0".
+# PreserveFileTimes 0
+
# The lock file to use. This ensures only one geoipupdate process can run at a
# time.
# Defaults to ".geoipupdate.lock" under the DatabaseDirectory.
diff --git a/configure b/configure
index 931594e..0a09408 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for geoipupdate 2.4.0.
+# Generated by GNU Autoconf 2.69 for geoipupdate 2.5.0.
#
# Report bugs to <support@maxmind.com>.
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='geoipupdate'
PACKAGE_TARNAME='geoipupdate'
-PACKAGE_VERSION='2.4.0'
-PACKAGE_STRING='geoipupdate 2.4.0'
+PACKAGE_VERSION='2.5.0'
+PACKAGE_STRING='geoipupdate 2.5.0'
PACKAGE_BUGREPORT='support@maxmind.com'
PACKAGE_URL=''
@@ -1325,7 +1325,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures geoipupdate 2.4.0 to adapt to many kinds of systems.
+\`configure' configures geoipupdate 2.5.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1396,7 +1396,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of geoipupdate 2.4.0:";;
+ short | recursive ) echo "Configuration of geoipupdate 2.5.0:";;
esac
cat <<\_ACEOF
@@ -1506,7 +1506,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-geoipupdate configure 2.4.0
+geoipupdate configure 2.5.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1983,7 +1983,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by geoipupdate $as_me 2.4.0, which was
+It was created by geoipupdate $as_me 2.5.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -4217,7 +4217,7 @@ fi
# Define the identity of the package.
PACKAGE='geoipupdate'
- VERSION='2.4.0'
+ VERSION='2.5.0'
cat >>confdefs.h <<_ACEOF
@@ -13282,7 +13282,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by geoipupdate $as_me 2.4.0, which was
+This file was extended by geoipupdate $as_me 2.5.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -13339,7 +13339,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-geoipupdate config.status 2.4.0
+geoipupdate config.status 2.5.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 124dfd3..6b3cd4f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
dnl AM_CONFIG_HEADER(config.h)
-AC_INIT([geoipupdate], [2.4.0],[support@maxmind.com],[geoipupdate])
+AC_INIT([geoipupdate], [2.5.0],[support@maxmind.com],[geoipupdate])
AC_GNU_SOURCE
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_SRCDIR([bin/geoipupdate.c])
diff --git a/man/GeoIP.conf.5.in b/man/GeoIP.conf.5.in
index 11130a8..b595c36 100644
--- a/man/GeoIP.conf.5.in
+++ b/man/GeoIP.conf.5.in
@@ -1,4 +1,4 @@
-.TH GeoIP.conf 5 "25 Sep 2013"
+.TH GeoIP.conf 5 "26 Oct 2017"
.UC 4
.SH NAME
GeoIP.conf - Configuration file for geoipupdate
@@ -17,15 +17,17 @@ CONF_DIR/GeoIP.conf
.PP
.SS Required settings:
.TP
-.B UserId
-Your MaxMind user ID.
+.B AccountID
+Your MaxMind account ID. This was formerly known as
+.BR UserId ".
.TP
.B LicenseKey
Your case-sensitive MaxMind license key.
.TP
-.B ProductIds
-List of product IDs. Product IDs may consist of letters, digits, and dashes
-(e.g., "GeoIP2-City", "106").
+.B EditionIDs
+List of database edition IDs. Edition IDs may consist of letters, digits, and
+dashes (e.g., "GeoIP2-City", "106"). Note: this was formerly called
+.BR ProductIds ".
.PP
.SS Optional settings:
.PP
@@ -52,11 +54,22 @@ The proxy user name and password, separated by a colon. For instance,
.TP
.B SkipPeerVerification
Skip peer verification when using
-.BR https ". Valid values are " 0 " and " 1 ". The default is " 0 ".
+.BR https ". Valid values are " 0 " or " 1 ". The default is " 0 ".
.TP
.B SkipHostnameVerification
Skip the host name verification when using
-.BR https ". This option is either " 0 " and " 1 ". The default is " 0 ".
+.BR https ". This option is either " 0 " or " 1 ". The default is " 0 ".
+.TP
+.B PreserveFileTimes
+Whether to preserve modification times of files downloaded from the server.
+This option is either
+.BR 0 " or " 1 ". The default is " 0 ".
+.TP
+.B LockFile
+The lock file to use. This ensures only one
+.B geoipupdate
+process can run at a time. The default is
+.BR .geoipupdate.lock " under the " DatabaseDirectory .
.SH FILES
.PP
.TP