Change the magic number used to introduce a trie file, so that instead
[sgt/agedu] / agedu.c
diff --git a/agedu.c b/agedu.c
index 08286a5..1847e2c 100644 (file)
--- a/agedu.c
+++ b/agedu.c
@@ -341,6 +341,8 @@ static void text_query(const void *mappedfile, const char *querydir,
         HELPOPT("[--scan,--load] keep real atimes on directories") \
     NOVAL(NODIRATIME) LONG(no_dir_atime) LONG(no_dir_atimes) \
         HELPOPT("[--scan,--load] fake atimes on directories") \
+    NOVAL(NOEOF) LONG(no_eof) LONG(noeof) \
+        HELPOPT("[--web] do not close web server on EOF") \
     NOVAL(MTIME) LONG(mtime) \
         HELPOPT("[--scan] use mtime instead of atime") \
     NOVAL(SHOWFILES) LONG(files) \
@@ -359,6 +361,8 @@ static void text_query(const void *mappedfile, const char *querydir,
         HELPARG("filename") HELPOPT("[--web] read HTTP Basic user/pass from file") \
     VAL(AUTHFD) LONG(auth_fd) \
         HELPARG("fd") HELPOPT("[--web] read HTTP Basic user/pass from fd") \
+    VAL(HTMLTITLE) LONG(title) \
+        HELPARG("title") HELPOPT("[--web,--html] title prefix for web pages") \
     VAL(DEPTH) SHORT(d) LONG(depth) LONG(max_depth) LONG(maximum_depth) \
         HELPARG("levels") HELPOPT("[--text,--html] recurse to this many levels") \
     VAL(MINAGE) SHORT(a) LONG(age) LONG(min_age) LONG(minimum_age) \
@@ -498,10 +502,11 @@ int main(int argc, char **argv)
     time_t now = time(NULL);
     time_t textcutoff = now, htmlnewest = now, htmloldest = now;
     int htmlautoagerange = 1;
-    const char *httpserveraddr = NULL;
-    int httpserverport = 0;
+    const char *httpserveraddr = "localhost";
+    const char *httpserverport = NULL;
     const char *httpauthdata = NULL;
     const char *outfile = NULL;
+    const char *html_title = PNAME;
     int auth = HTTPD_AUTH_MAGIC | HTTPD_AUTH_BASIC;
     int progress = 1;
     struct inclusion_exclusion *inex = NULL;
@@ -510,6 +515,7 @@ int main(int argc, char **argv)
     int depth = -1, gotdepth = 0;
     int fakediratimes = 1;
     int mtime = 0;
+    int closeoneof = 1;
     int showfiles = 0;
 
 #ifdef DEBUG_MAD_OPTION_PARSING_MACROS
@@ -767,6 +773,9 @@ int main(int argc, char **argv)
                  case OPT_MTIME:
                    mtime = 1;
                    break;
+                  case OPT_NOEOF:
+                    closeoneof = 0;
+                    break;
                  case OPT_DATAFILE:
                    filename = optval;
                    break;
@@ -785,6 +794,9 @@ int main(int argc, char **argv)
                  case OPT_OUTFILE:
                    outfile = optval;
                    break;
+                  case OPT_HTMLTITLE:
+                    html_title = optval;
+                    break;
                  case OPT_MINAGE:
                    textcutoff = parse_age(now, optval);
                    break;
@@ -809,10 +821,13 @@ int main(int argc, char **argv)
                        else
                            port = optval;
                        port += strcspn(port, ":");
-                       if (port)
+                       if (port && *port)
                            *port++ = '\0';
-                       httpserveraddr = optval;
-                       httpserverport = atoi(port);
+                        if (!strcmp(optval, "ANY"))
+                            httpserveraddr = NULL;
+                        else
+                            httpserveraddr = optval;
+                       httpserverport = port;
                    }
                    break;
                  case OPT_AUTH:
@@ -1131,7 +1146,6 @@ int main(int argc, char **argv)
                prevbuf[0] = '\0';
                tf = triewalk_next(tw, buf);
                assert(tf);
-               prevtf = NULL;         /* placate lint */
                while (1) {
                    int i;
 
@@ -1166,9 +1180,6 @@ int main(int argc, char **argv)
                        triewalk_rebase(tw, mappedfile);
                        diff = (const unsigned char *)mappedfile -
                            (const unsigned char *)oldfile;
-                       if (prevtf)
-                           prevtf = (const struct trie_file *)
-                               (((const unsigned char *)prevtf) + diff);
                        if (tf)
                            tf = (const struct trie_file *)
                                (((const unsigned char *)tf) + diff);
@@ -1235,7 +1246,8 @@ int main(int argc, char **argv)
                indexbuild_free(ib);
 
                munmap(mappedfile, totalsize);
-               ftruncate(fd, realsize);
+               if (ftruncate(fd, realsize) < 0)
+                    fatal("%s: truncate: %s\n", filename, strerror(errno));
                close(fd);
                printf("Final index file size = %llu bytes\n",
                       (unsigned long long)realsize);
@@ -1260,6 +1272,11 @@ int main(int argc, char **argv)
                perror(PNAME ": mmap");
                return 1;
            }
+            if (!trie_check_magic(mappedfile)) {
+               fprintf(stderr, "%s: %s: magic numbers did not match\n"
+                        "%s: check that the index was built by this version of agedu on this platform\n", PNAME, filename, PNAME);
+               return 1;
+            }
            pathsep = trie_pathsep(mappedfile);
 
            /*
@@ -1343,11 +1360,49 @@ int main(int argc, char **argv)
                }
                return 1;
            }
+           if (!trie_check_magic(mappedfile)) {
+               fprintf(stderr, "%s: %s: magic numbers did not match\n"
+                        "%s: check that the index was built by this version of agedu on this platform\n", PNAME, filename, PNAME);
+               if (!querydir) {
+                   printf("Status: 500\nContent-type: text/html\n\n"
+                          "<html><head>"
+                          "<title>500 Internal Server Error</title>"
+                          "</head><body>"
+                          "<h1>500 Internal Server Error</h1>"
+                          "<p><code>agedu</code> suffered an internal error."
+                          "</body></html>\n");
+                   return 0;
+               }
+               return 1;
+           }
            pathsep = trie_pathsep(mappedfile);
 
            maxpathlen = trie_maxpathlen(mappedfile);
            pathbuf = snewn(maxpathlen, char);
 
+           if (!querydir || !gotdepth) {
+               /*
+                * Single output file.
+                */
+               if (!querydir) {
+                    cfg.uriformat = "/%|/%p/%|%|/%p";
+               } else {
+                   cfg.uriformat = NULL;
+               }
+               cfg.autoage = htmlautoagerange;
+               cfg.oldest = htmloldest;
+               cfg.newest = htmlnewest;
+               cfg.showfiles = showfiles;
+           } else {
+                cfg.uriformat = "/index.html%|/%/p.html";
+                cfg.fileformat = "/index.html%|/%/p.html";
+               cfg.autoage = htmlautoagerange;
+               cfg.oldest = htmloldest;
+               cfg.newest = htmlnewest;
+               cfg.showfiles = showfiles;
+           }
+            cfg.html_title = html_title;
+
            if (!querydir) {
                /*
                 * If we're run in --cgi mode, read PATH_INFO to get
@@ -1358,13 +1413,27 @@ int main(int argc, char **argv)
                if (!path_info)
                    path_info = "";
 
+                /*
+                 * Parse the path.
+                 */
+                if (!html_parse_path(mappedfile, path_info, &cfg, &xi)) {
+                   printf("Status: 404\nContent-type: text/html\n\n"
+                          "<html><head>"
+                          "<title>404 Not Found</title>"
+                          "</head><body>"
+                          "<h1>400 Not Found</h1>"
+                          "<p>Invalid <code>agedu</code> pathname."
+                          "</body></html>\n");
+                   return 0;
+               }
+
                /*
-                * Because we need relative links to go to the
-                * right place, it's important that our
-                * PATH_INFO should contain a slash right at the
-                * start, and no slashes anywhere else.
+                * If the path was parseable but not canonically
+                * expressed, return a redirect to the canonical
+                * version.
                 */
-               if (path_info[0] != '/') {
+                char *canonpath = html_format_path(mappedfile, &cfg, xi);
+               if (strcmp(canonpath, path_info)) {
                    char *servername = getenv("SERVER_NAME");
                    char *scriptname = getenv("SCRIPT_NAME");
                    if (!servername || !scriptname) {
@@ -1386,7 +1455,7 @@ int main(int argc, char **argv)
                        return 0;
                    }
                    printf("Status: 301\n"
-                          "Location: http://%s/%s/\n"
+                          "Location: http://%s/%s%s\n"
                           "Content-type: text/html\n\n"
                           "<html><head>"
                           "<title>301 Moved</title>"
@@ -1394,39 +1463,10 @@ int main(int argc, char **argv)
                           "<h1>301 Moved</h1>"
                           "<p>Moved."
                           "</body></html>\n",
-                          servername, scriptname);
-                   return 0;
-               } else if (strchr(path_info+1, '/')) {
-                   printf("Status: 404\nContent-type: text/html\n\n"
-                          "<html><head>"
-                          "<title>404 Not Found</title>"
-                          "</head><body>"
-                          "<h1>400 Not Found</h1>"
-                          "<p>Invalid <code>agedu</code> pathname."
-                          "</body></html>\n");
+                          servername, scriptname, canonpath);
                    return 0;
                }
-               xi = atoi(path_info + 1);
 
-               if (xi >= trie_count(mappedfile)) {
-                   printf("Status: 404\nContent-type: text/html\n\n"
-                          "<html><head>"
-                          "<title>404 Not Found</title>"
-                          "</head><body>"
-                          "<h1>404 Not Found</h1>"
-                          "<p>This is not a valid pathname index."
-                          "</body></html>\n");
-                   return 0;
-               } else if (!index_has_root(mappedfile, xi)) {
-                   printf("Status: 404\nContent-type: text/html\n\n"
-                          "<html><head>"
-                          "<title>404 Not Found</title>"
-                          "</head><body>"
-                          "<h1>404 Not Found</h1>"
-                          "<p>Pathname index out of range."
-                          "</body></html>\n");
-                   return 0;
-               }
            } else {
                /*
                 * In ordinary --html mode, process a query
@@ -1462,16 +1502,6 @@ int main(int argc, char **argv)
                /*
                 * Single output file.
                 */
-               if (!querydir) {
-                   cfg.format = "%.0lu";  /* use crosslinks in --cgi mode */
-               } else {
-                   cfg.format = NULL;
-               }
-               cfg.rootpage = NULL;
-               cfg.autoage = htmlautoagerange;
-               cfg.oldest = htmloldest;
-               cfg.newest = htmlnewest;
-               cfg.showfiles = showfiles;
                html = html_query(mappedfile, xi, &cfg, 1);
                if (querydir && outfile != NULL) {
                    FILE *fp = fopen(outfile, "w");
@@ -1521,12 +1551,6 @@ int main(int argc, char **argv)
                make_successor(pathbuf);
                xi2 = trie_before(mappedfile, pathbuf);
 
-               cfg.format = "%lu.html";
-               cfg.rootpage = "index.html";
-               cfg.autoage = htmlautoagerange;
-               cfg.oldest = htmloldest;
-               cfg.newest = htmlnewest;
-               cfg.showfiles = showfiles;
                if (html_dump(mappedfile, xi, xi2, depth, &cfg, prefix))
                    return 1;
            }
@@ -1553,6 +1577,11 @@ int main(int argc, char **argv)
                perror(PNAME ": mmap");
                return 1;
            }
+            if (!trie_check_magic(mappedfile)) {
+               fprintf(stderr, "%s: %s: magic numbers did not match\n"
+                        "%s: check that the index was built by this version of agedu on this platform\n", PNAME, filename, PNAME);
+               return 1;
+            }
            pathsep = trie_pathsep(mappedfile);
 
            maxpathlen = trie_maxpathlen(mappedfile);
@@ -1585,17 +1614,23 @@ int main(int argc, char **argv)
                perror(PNAME ": mmap");
                return 1;
            }
+            if (!trie_check_magic(mappedfile)) {
+               fprintf(stderr, "%s: %s: magic numbers did not match\n"
+                        "%s: check that the index was built by this version of agedu on this platform\n", PNAME, filename, PNAME);
+               return 1;
+            }
            pathsep = trie_pathsep(mappedfile);
 
            dcfg.address = httpserveraddr;
            dcfg.port = httpserverport;
+           dcfg.closeoneof = closeoneof;
            dcfg.basicauthdata = httpauthdata;
-           pcfg.format = NULL;
-           pcfg.rootpage = NULL;
+           pcfg.uriformat = "/%|/%p/%|%|/%p";
            pcfg.autoage = htmlautoagerange;
            pcfg.oldest = htmloldest;
            pcfg.newest = htmlnewest;
            pcfg.showfiles = showfiles;
+            pcfg.html_title = html_title;
            run_httpd(mappedfile, auth, &dcfg, &pcfg);
            munmap(mappedfile, totalsize);
        } else if (mode == REMOVE) {