]> pd.if.org Git - zpackage/blobdiff - src/fetchurl.c
print warning if host cert changed
[zpackage] / src / fetchurl.c
index 1b337244421df9f0f74b7aa5a2d99186670ecd60..e09a43755d4aa03eb947e06577b19297753dce99 100644 (file)
@@ -15,7 +15,6 @@
 #include <fcntl.h>
 
 #include "tlse.h"
-#define MARK fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__)
 
 struct tls_uri {
        char *scheme;
@@ -210,6 +209,9 @@ int verify_first(struct TLSContext *context, struct TLSCertificate **chain, int
 
                close(trustdb);
                tls_buffer_free(&tbuf);
+               if (!match) {
+                       fprintf(stderr, "host %s certificate changed\n", host);
+               }
                return match ? no_error : bad_certificate;
        } while (!tbuf.error);
 
@@ -508,6 +510,53 @@ static void fake_header(struct io *io, int fd) {
        tls_buffer_append(hdr, "\r\n", 2);
 }
 
+char *pathlast(char *path) {
+       char *last = 0;
+       size_t len = 0;
+
+       if (path == 0) {
+               return 0;
+       }
+
+       while (*path == '/') {
+               path++;
+       }
+
+       do {
+               last = path;
+               len = 0;
+               while (*path && *path != '/') {
+                       path++;
+                       len++;
+               }
+               while (*path == '/') {
+                       path++;
+               }
+       } while (*path);
+
+       if (len == 0) {
+               return 0;
+       }
+
+       return strndup(last, len);
+}
+
+static time_t file_mtime(char *path) {
+       struct stat st;
+       int rv;
+
+       rv = stat(path, &st);
+       if (rv == -1) {
+               if (errno == ENOENT) {
+                       return 0;
+               } 
+               perror("stat failed:");
+               return -1;
+       }
+
+       return st.st_mtime;
+}
+
 int main(int ac, char *av[]) {
        int sockfd, port = -1, rv;
        ssize_t ret;
@@ -519,10 +568,10 @@ int main(int ac, char *av[]) {
 #endif
        char *req_file = 0;
        char *host = 0;
-       struct tls_uri uri;
+       struct tls_uri uri = { 0 };
        char *outfile = 0;
        int raw = 0, head = 0;
-       int out = 1;
+       int out = 1; /* output file descriptor */
        int use_tls = 0;
        struct io io = { {0}, 0, -1, 0, 0, 0, 0, 0 };
        struct TLSContext *clientssl = 0;
@@ -536,13 +585,14 @@ int main(int ac, char *av[]) {
        size_t header_len;
        char *url = 0;
        int redirs = 0, redirlimit = 50, printstatus = 0;
-       int verifypolicy = 1;
+       int verifypolicy = 1, calcoutfile = 0, ifnewer = 0;
 
        ltc_mp = tfm_desc;
 
-       while ((option = getopt(ac, av, "o:rIfz:#R:SkK")) != -1) {
+       while ((option = getopt(ac, av, "o:OrIfz:np#R:SkK")) != -1) {
                switch (option) {
                        case 'o': outfile = optarg; break;
+                       case 'O': calcoutfile = 1; break;
                        case 'S': printstatus = 1; head = 1; break;
                        case 'k': verifypolicy = 0; break;
                        case 'K': verifypolicy = 2; break;
@@ -550,7 +600,9 @@ int main(int ac, char *av[]) {
                        case 'r': raw = 1; break;
                        case 'f': failsilent = 1; break;
                        case 'z': lmfile = optarg; break;
+                       case 'n': ifnewer = 1; break;
                        case 'R': redirlimit = strtol(optarg, 0, 10); break;
+                       case 'p':
                        case '#': progressbar = 1; break;
                        default:
                                  exit(EXIT_FAILURE);
@@ -563,34 +615,44 @@ int main(int ac, char *av[]) {
                exit(EXIT_FAILURE);
        }
 
+       url = strdup(av[optind]);
+       if (!url) {
+               exit(EXIT_FAILURE);
+       }
+
        io.last_modified = 0;
-       if (lmfile) {
-               struct stat st;
-               int rv;
-               struct tm *mtime;
-               time_t ts;
 
-               rv = stat(lmfile, &st);
-               if (rv == -1) {
-                       perror("stat failed:");
+       if (calcoutfile && !outfile) {
+               tls_parse_uri(url, &uri);
+               outfile = pathlast(uri.path);
+               /* outfile leaks memory here, so if this
+                * were turned into a library function,
+                * we'd need to track it
+                */
+               if (!outfile) {
+                       fprintf(stderr, "unable to determine outfile\n");
                        exit(EXIT_FAILURE);
                }
-               ts = st.st_mtime;
-               io.last_modified = ts;
-               mtime = gmtime(&ts);
-               strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime);
        }
 
-       url = strdup(av[optind]);
-       if (!url) {
-               exit(EXIT_FAILURE);
+       if (ifnewer && outfile && !lmfile) {
+               lmfile = outfile;
        }
 
-       if (outfile) {
-               out = open(outfile, O_WRONLY|O_CREAT, 0600);
-               if (out == -1) {
-                       perror("can't open output file:");
+       if (lmfile) {
+               struct tm *mtime;
+               time_t ts;
+
+               ts = file_mtime(lmfile);
+
+               if (ts == -1) {
                        exit(EXIT_FAILURE);
+               } else if (ts != 0) {
+                       io.last_modified = ts;
+                       mtime = gmtime(&ts);
+                       strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime);
+               } else {
+                       lmfile = 0;
                }
        }
 
@@ -603,6 +665,7 @@ int main(int ac, char *av[]) {
                tls_free_uri(&uri);
                io.response.len = 0;
                request.len = 0;
+               eoh = 0;
 
                tls_parse_uri(url, &uri);
                host = uri.host;
@@ -716,12 +779,16 @@ int main(int ac, char *av[]) {
                parse_header(&io);
 
                switch (io.status_code) {
+                       case 304:
+                               progressbar = 0;
+                               break;
                        case 301:
                        case 302:
                        case 303:
                        case 307:
                                free(url);
                                url = strdup(io.redirect);
+                               close(io.socket);
                                continue;
                                break;
                }
@@ -744,6 +811,14 @@ int main(int ac, char *av[]) {
                        }
                }
 
+               if (outfile) {
+                       out = open(outfile, O_WRONLY|O_CREAT, 0600);
+                       if (out == -1) {
+                               perror("can't open output file:");
+                               exit(EXIT_FAILURE);
+                       }
+               }
+
                do {
                        write(out, io.response.buffer, io.response.len);
                        ret = io.response.len;
@@ -754,11 +829,8 @@ int main(int ac, char *av[]) {
                                        pdots(50, '.', total, total+ret,
                                                        io.content_length);
                                } else {
-                                       int old = total / 1000000;
-                                       int new = (total+ret)/1000000;
-                                       while (old < new) {
-                                               putc('.',stderr);
-                                       }
+                                       putc('\r', stderr);
+                                       fprintf(stderr, "%zu", total+ret);
                                }
                                total += ret;
                        }
@@ -771,7 +843,12 @@ int main(int ac, char *av[]) {
                if (ret < 0) {
                        fprintf(stderr, "%s read error %zd\n", uri.scheme, ret);
                }
-               /* futimens(out, ...) */
+               struct timespec ts[2];
+               ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT;
+               ts[1].tv_sec = io.last_modified;
+               ts[1].tv_nsec = 0;
+
+               futimens(out, ts);
                close(out);
                tls_buffer_free(&io.response);
                break;
@@ -788,5 +865,5 @@ int main(int ac, char *av[]) {
                putc('\n',stderr);
        }
 
-       return io.status_code == 200 ? 0 : EXIT_FAILURE;
+       return io.status_code < 400 ? 0 : EXIT_FAILURE;
 }