merge from latest changes in snap
authortridge <>
Sun, 6 Jan 2002 13:41:14 +0000 (13:41 +0000)
committertridge <>
Sun, 6 Jan 2002 13:41:14 +0000 (13:41 +0000)
tserver/Makefile
tserver/cgi.c
tserver/cgi.h
tserver/includes.h
tserver/template.c
tserver/template.h
tserver/tserver.c
tserver/util.c

index e0a7a1e..b8069fe 100644 (file)
@@ -9,10 +9,13 @@ INCLUDES = includes.h cgi.h template.h
        @echo Compiling $*.c
        @$(CC) -c $(CPPFLAGS) $(CFLAGS) $*.c 
 
+all: tserver
+
 tserver: $(OBJS)
        @echo Linking $@
        @$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
        @strip $@
 
 clean:
-       /bin/rm -f *.o tserver *~
+       /bin/rm -f *.o tserver *~ files/*~
+
index eee7bd4..4888f42 100644 (file)
 
 #include "includes.h"
 
+#define CONTENT_DISPOSITION "Content-Disposition:"
+#define CONTENT_TYPE "Content-Type:"
+#define MULTIPART_FORM_DATA "multipart/form-data"
+#define CRLF "\r\n"
+
 /* 
    inplace handling of + and % escapes in http variables 
 */
@@ -41,22 +46,19 @@ static void unescape(char *p)
   read one line from a file, allocating space as need be
   adjust length on return
 */
-static char *grab_line(FILE *f, int *length)
+static char *grab_line(FILE *f, const char *terminator, int *length)
 {
-       char *ret = NULL;
+       int len = 1024;
+       char *ret = malloc(len);
        int i = 0;
-       int len = 0;
+       int tlen = strlen(terminator);
 
        while (*length) {
                int c;
        
                if (i == len) {
-                       char *ret2;
-                       if (len == 0) len = 1024;
-                       else len *= 2;
-                       ret2 = (char *)realloc(ret, len);
-                       if (!ret2) return ret;
-                       ret = ret2;
+                       len *= 2;
+                       ret = realloc(ret, len);
                }
        
                c = fgetc(f);
@@ -67,18 +69,19 @@ static char *grab_line(FILE *f, int *length)
                        break;
                }
                
-               if (c == '\r') continue;
-
-               if (strchr("\n&", c)) break;
-
                ret[i++] = c;
+
+               if (memcmp(terminator, &ret[i-tlen], tlen) == 0) {
+                       i -= tlen;
+                       break;
+               }
        }
-       
 
        ret[i] = 0;
        return ret;
 }
 
+
 /*
   add a name/value pair to the list of cgi variables 
 */
@@ -86,11 +89,14 @@ static void put(struct cgi_state *cgi, const char *name, const char *value)
 {
        struct cgi_var *var;
        int len;
+       char *cgi_name, *p;
 
        if (!name || !value) return;
+
        var = malloc(sizeof(*var));
+       memset(var, 0, sizeof(*var));
        var->next = cgi->variables;
-       
+
        /* trim leading spaces */
        while (*name && (*name == '+' || *name == ' ')) name++;
 
@@ -106,31 +112,163 @@ static void put(struct cgi_state *cgi, const char *name, const char *value)
                len--;
        }
 
+       for (p=var->name; *p; p++) {
+               if (!isalnum(*p) && !strchr("_-", *p)) {
+                       *p = '_';
+               }
+       }
+
        cgi->variables = var;
+       asprintf(&cgi_name, "CGI_%s", var->name);
+       cgi->tmpl->put(cgi->tmpl, cgi_name, var->value, NULL);
+       free(cgi_name);
 }
 
 
 /*
-  load all the variables passed to the CGI program. May have multiple variables
-  with the same name and the same or different values. 
+  parse a url encoded form
 */
-static void load_variables(struct cgi_state *cgi)
+static void load_urlencoded(struct cgi_state *cgi)
 {
+       int len = cgi->content_length;
        char *line;
-       char *p, *s, *tok;
-       int len;
+       char *p;
        FILE *f = stdin;
 
-       len = cgi->content_length;
+       while (len && (line=grab_line(f, "&", &len))) {
+               p = strchr(line,'=');
+               if (p) {
+                       *p = 0;
+                       put(cgi, line, p+1);
+               }
+               free(line);
+       }
+}
 
-       if (len > 0 && cgi->request_post) {
-               while (len && (line=grab_line(f, &len))) {
-                       p = strchr(line,'=');
+/*
+  parse a single element of a multipart encoded form
+  It's rather more complex than I would like :(
+*/
+static int load_one_part(struct cgi_state *cgi, FILE *f, int *len, char *boundary)
+{
+       char *line;
+       char *name=NULL;
+       char *content;
+       char *filename=NULL;
+       unsigned content_len=0, content_alloc=1024;
+       unsigned boundary_len = strlen(boundary);
+       int c;
+       int raw_data = 0;
+
+       while (*len && (line=grab_line(f, CRLF, len))) {
+               if (*line == 0) break;
+               if (strcmp(line,"--") == 0) return 1;
+               if (strncasecmp(line, CONTENT_TYPE, 
+                               strlen(CONTENT_TYPE)) == 0) {
+                       raw_data = 1;
+               }
+               if (strncasecmp(line, CONTENT_DISPOSITION, 
+                               strlen(CONTENT_DISPOSITION)) == 0) {
+                       char *p = strstr(line,"; name=");
+                       if (!p) continue;
+                       p += 7;
+                       if (*p == '"') p++;
+                       name = strndup(p, strcspn(p, "\";"));
+                       p = strstr(line,"; filename=\"");
                        if (p) {
-                               *p = 0;
-                               put(cgi, line, p+1);
+                               p += 12;
+                               filename = strndup(p, strcspn(p, "\";"));
                        }
-                       free(line);
+               }
+       }
+       
+       content = malloc(content_alloc);
+       
+       while (*len && (c = fgetc(f)) != EOF) {
+               (*len)--;
+               if (content_len >= (content_alloc-1)) {
+                       content_alloc *= 2;
+                       content = realloc(content, content_alloc);
+               }
+               content[content_len++] = c;
+               /* we keep grabbing content until we hit a boundary */
+               if (memcmp(boundary, &content[content_len-boundary_len], 
+                          boundary_len) == 0 &&
+                   memcmp("--", &content[content_len-boundary_len-2], 2) == 0) {
+                       content_len -= boundary_len+4;
+                       if (name) {
+                               if (raw_data) {
+                                       put(cgi, name, filename?filename:"");
+                                       cgi->variables->content = content;
+                                       cgi->variables->content_len = content_len;
+                               } else {
+                                       content[content_len] = 0;
+                                       put(cgi, name, content);
+                                       free(name);
+                                       free(content);
+                               }
+                       } else {
+                               free(content);
+                       }
+                       fgetc(f); fgetc(f);
+                       (*len) -= 2;
+                       return 0;
+               }
+       }
+
+       if (filename) free(filename);
+
+       return 1;
+}
+
+/*
+  parse a multipart encoded form (for file upload)
+  see rfc1867
+*/
+static void load_multipart(struct cgi_state *cgi)
+{
+       char *boundary;
+       FILE *f = stdin;
+       int len = cgi->content_length;
+       char *line;
+
+       if (!cgi->content_type) return;
+       boundary = strstr(cgi->content_type, "boundary=");
+       if (!boundary) return;
+       boundary += 9;
+       trim_tail(boundary, CRLF);
+       line = grab_line(f, CRLF, &len);
+       if (strncmp(line,"--", 2) != 0 || 
+           strncmp(line+2,boundary,strlen(boundary)) != 0) {
+               fprintf(stderr,"Malformed multipart?\n");
+               free(line);
+               return;
+       }
+
+       if (strcmp(line+2+strlen(boundary), "--") == 0) {
+               /* the end is only the beginning ... */
+               free(line);
+               return;
+       }
+
+       free(line);
+       while (load_one_part(cgi, f, &len, boundary) == 0) ;
+}
+
+/*
+  load all the variables passed to the CGI program. May have multiple variables
+  with the same name and the same or different values. 
+*/
+static void load_variables(struct cgi_state *cgi)
+{
+       char *p, *s, *tok;
+
+       if (cgi->content_length > 0 && cgi->request_post) {
+               if (strncmp(cgi->content_type, MULTIPART_FORM_DATA, 
+                           strlen(MULTIPART_FORM_DATA)) == 0) {
+                       load_multipart(cgi);
+               } else {
+                       load_urlencoded(cgi);
                }
        }
 
@@ -166,12 +304,21 @@ static const char *get(struct cgi_state *cgi, const char *name)
        return NULL;
 }
 
-/* set a variable in the cgi template from a cgi variable */
-static void setvar(struct cgi_state *cgi, const char *name)
+/*
+   return the content of a binary cgi variable (for file upload)
+*/
+static const char *get_content(struct cgi_state *cgi, const char *name, unsigned *size)
 {
-       cgi->tmpl->put(cgi->tmpl, name, cgi->get(cgi, name));
-}
+       struct cgi_var *var;
 
+       for (var = cgi->variables; var; var = var->next) {
+               if (strcmp(var->name, name) == 0) {
+                       *size = var->content_len;
+                       return var->content;
+               }
+       }
+       return NULL;
+}
 
 /*
   tell a browser about a fatal error in the http processing
@@ -256,7 +403,8 @@ static int setup(struct cgi_state *cgi)
 
        /* we are a mini-web server. We need to read the request from stdin */
        while (fgets(line, sizeof(line)-1, stdin)) {
-               if (line[0] == '\r' || line[0] == '\n') break;
+               trim_tail(line, CRLF);
+               if (line[0] == 0) break;
                if (strncasecmp(line,"GET ", 4)==0) {
                        cgi->got_request = 1;
                        url = strdup(&line[4]);
@@ -271,6 +419,8 @@ static int setup(struct cgi_state *cgi)
                        return -1;
                } else if (strncasecmp(line,"Content-Length: ", 16)==0) {
                        cgi->content_length = atoi(&line[16]);
+               } else if (strncasecmp(line,"Content-Type: ", 14)==0) {
+                       cgi->content_type = strdup(&line[14]);
                }
                /* ignore all other requests! */
        }
@@ -284,9 +434,6 @@ static int setup(struct cgi_state *cgi)
        if ((p = strchr(url,' ')) || (p=strchr(url,'\t'))) {
                *p = 0;
        }
-       while (*url && strchr("\r\n",url[strlen(url)-1])) {
-               url[strlen(url)-1] = 0;
-       }
 
        /* anything following a ? in the URL is part of the query string */
        if ((p=strchr(url,'?'))) {
@@ -330,7 +477,7 @@ static struct cgi_state cgi_base = {
        http_header,
        load_variables,
        get,
-       setvar,
+       get_content,
        http_error,
        download,
        
index 22b4e1d..008af83 100644 (file)
@@ -21,6 +21,8 @@ struct cgi_var {
        struct cgi_var *next;
        char *name;
        char *value;
+       char *content;
+       unsigned content_len;
 };
 
 struct cgi_state {
@@ -30,7 +32,7 @@ struct cgi_state {
        enum MIME_TYPE (*http_header)(struct cgi_state *, const char *);
        void (*load_variables)(struct cgi_state *);
        const char *(*get)(struct cgi_state *, const char *);
-       void (*setvar)(struct cgi_state *, const char *);
+       const char *(*get_content)(struct cgi_state *, const char *, unsigned *size);
        void (*http_error)(struct cgi_state *cgi, 
                           const char *err, const char *header, const char *info);
        void (*download)(struct cgi_state *cgi, const char *path);
@@ -38,6 +40,7 @@ struct cgi_state {
        /* data */
        struct cgi_var *variables;
        struct template_state *tmpl;
+       char *content_type;
        int content_length;
        int request_post;
        char *query_string;
index 594e185..35f5322 100644 (file)
@@ -8,6 +8,7 @@
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <ctype.h>
+#include <getopt.h>
 #include <time.h>
 #include <string.h>
 #include <netdb.h>
@@ -31,18 +32,15 @@ typedef unsigned BOOL;
 #define True 1
 #define False 0
 
-#define TSERVER_PORT 8003
-#define TSERVER_LOGFILE "tserver.log"
+#define TSERVER_PORT 80
 
 #define MMAP_FAILED ((void *)-1)
 
 /* prototypes */
-void tcp_listener(int port, const char *logfile, void (*fn)(void));
+void tcp_listener(int port, void (*fn)(void));
 
 void *map_file(const char *fname, size_t *size);
 void unmap_file(void *p, size_t size);
 void *x_malloc(size_t size);
-
-
-
+void trim_tail(char *s, char *trim_chars);
 
index 3cc2450..1436581 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "includes.h"
 
+static void process_tag(struct template_state *tmpl, const char *tag);
+
 /* 
    fetch a variable from the template variables list 
 */
@@ -37,7 +39,8 @@ static struct template_var *find_var(struct template_state *tmpl, const char *na
 /*
   add a name/value pair to the list of template variables 
 */
-static void put(struct template_state *tmpl, const char *name, const char *value)
+static void put(struct template_state *tmpl, const char *name, 
+               const char *value, template_fn fn)
 {
        struct template_var *var;
        if (!name || !value) return;
@@ -50,6 +53,7 @@ static void put(struct template_state *tmpl, const char *name, const char *value
                var->next = tmpl->variables;
                tmpl->variables = var;
                var->name = strdup(name);
+               var->function = fn;
        }
        var->value = strdup(value);
 }
@@ -72,13 +76,26 @@ static void process_variable(struct template_state *tmpl, const char *tag)
        const char *v = tmpl->get(tmpl, tag);
        if (v) {
                printf("%s", v);
-       } else {
-               printf("%s $%s %s", START_TAG, tag, END_TAG);
+       }
+}
+
+/* process a template variable with quote escaping */
+static void process_escaped_variable(struct template_state *tmpl, const char *tag)
+{
+       const char *v = tmpl->get(tmpl, tag);
+       while (v && *v) {
+               if (*v == '"') {
+                       printf("&quot;");
+               } else {
+                       fputc(*v, stdout);
+               }
+               v++;
        }
 }
 
 /* process a inline shell script
    all current template variables are passed to the script in the environment
+   recursively processes any tags in the output of the script
  */
 static void process_shell(struct template_state *tmpl, const char *tag)
 {
@@ -88,33 +105,128 @@ static void process_shell(struct template_state *tmpl, const char *tag)
 
        if ((pid=fork()) == 0) {
                struct template_var *var;
+               FILE *p;
+               char *tag1=NULL;
+               int c, taglen=0;
+
                for (var = tmpl->variables; var; var = var->next) {
                        setenv(var->name, var->value, 1);
                } 
                dup2(1, 2);
-               _exit(execl("/bin/sh", "sh", "-c", tag, NULL));
+               p = popen(tag, "r");
+               if (!p) {
+                       printf("Failed to execute script\n");
+                       exit(1);
+               }
+               while ((c = fgetc(p)) != EOF) {
+                       int depth;
+
+                       tag1 = realloc(tag1, taglen+2);
+                       tag1[taglen++] = c; tag1[taglen] = 0;
+                       if (strncmp(tag1, START_TAG, taglen) != 0) {
+                               fputs(tag1, stdout);
+                               free(tag1); tag1 = NULL; taglen = 0;
+                               continue;
+                       }
+                       if (strcmp(tag1, START_TAG) != 0) continue;
+
+                       depth = 1;
+                       /* keep going until END_TAG */
+                       while (depth && (c = fgetc(p)) != EOF) {
+                               tag1 = realloc(tag1, taglen+2);
+                               tag1[taglen++] = c; tag1[taglen] = 0;
+                               if (strcmp(tag1+taglen-strlen(END_TAG), 
+                                          END_TAG) == 0) {
+                                       depth--;
+                               }
+                               if (strcmp(tag1+taglen-strlen(START_TAG), 
+                                          START_TAG) == 0) {
+                                       depth++;
+                               }
+                       }
+                       if (depth) continue;
+
+                       tag1[taglen-strlen(END_TAG)] = 0;
+                       process_tag(tmpl, tag1+strlen(START_TAG));
+                       free(tag1); tag1 = NULL; taglen = 0;
+               }
+               if (tag1) {
+                       fputs(tag1, stdout);
+                       free(tag1);
+               }
+               fflush(stdout);
+               fclose(p);
+               exit(1);
        }
        waitpid(pid, NULL, 0);
 }
 
+/* process a call into a C function setup with put_function() */
+static void process_c_call(struct template_state *tmpl, const char *tag)
+{
+       struct template_var *var;
+       char *name, *args, *p, *tok;
+       char **argv;
+       int argc=0;
+
+       if (!(p=strchr(tag, '('))) return;
+
+       name = strndup(tag, strcspn(tag, "("));
+
+       var = find_var(tmpl, name);
+       if (!var || !var->function) {
+               free(name);
+               return;
+       }
+
+       args = strndup(p+1, strcspn(p+1, ")"));
+
+       argv = malloc(sizeof(char *));
+       for (tok = strtok_r(args, ",", &p); tok; tok = strtok_r(NULL, ",", &p)) {
+               argv = realloc(argv, (argc+2)*sizeof(char *));
+               while (isspace(*tok)) tok++;
+               trim_tail(tok, " \t\r\n");
+               argv[argc++] = tok;
+       }
+       argv[argc] = NULL;
+
+       var->function(tmpl, name, var->value, argc, argv);
+       free(args);
+       free(name);
+}
+
 /*
   process a single tag
 */
 static void process_tag(struct template_state *tmpl, const char *tag)
 {
+       char *tag2;
+
        while (isspace(*tag)) tag++;
 
-       switch (*tag) {
+       tag2 = strdup(tag);
+       trim_tail(tag2, " \t\n\r");
+
+       switch (*tag2) {
        case '$':
-               process_variable(tmpl, tag+1);
+               process_variable(tmpl, tag2+1);
+               break;
+       case '%':
+               process_escaped_variable(tmpl, tag2+1);
                break;
        case '!':
-               process_shell(tmpl, tag+1);
+               process_shell(tmpl, tag2+1);
+               break;
+       case '@':
+               process_c_call(tmpl, tag2+1);
                break;
        default:
                /* an include file */
-               tmpl->process(tmpl, tag);
+               tmpl->process(tmpl, tag2);
        }
+       free(tag2);
+
+       fflush(stdout);
 }
 
 /*
@@ -124,9 +236,10 @@ static int process(struct template_state *tmpl, const char *filename)
 {
        size_t size, remaining;
        char *m, *mp;
-       char *contents;
        char *p, *s;
 
+       setvbuf(stdout, NULL, _IONBF, 0);
+
        mp = map_file(filename, &size);
        if (!mp) {
                fprintf(stderr,"Failed to map %s (%s)\n", 
@@ -143,11 +256,25 @@ static int process(struct template_state *tmpl, const char *filename)
        while (remaining && (p = strstr(m, START_TAG))) {
                const char *m0 = m;
                int len;
+               char *contents, *s2, *m2;
+               int depth=1;
 
                fwrite(m, 1, (p-m), stdout);
                m = p + strlen(START_TAG);
-               s = strstr(m, END_TAG);
-               if (!s) {
+               m2 = m;
+               while (depth) {
+                       s2 = strstr(m2, START_TAG);
+                       s = strstr(m2, END_TAG);
+                       if (!s) break;
+                       if (s2 && s2 < s) {
+                               depth++;
+                               m2 = s2 + strlen(START_TAG);
+                       } else {
+                               depth--;
+                               m2 = s + strlen(END_TAG);
+                       }
+               }
+               if (!s || depth) {
                        fprintf(stderr,"No termination of tag!\n");
                        return -1;
                }
@@ -155,13 +282,16 @@ static int process(struct template_state *tmpl, const char *filename)
                while (len && isspace(m[len-1])) len--;
                contents = strndup(m, len);
                process_tag(tmpl, contents);
+               free(contents);
                m = s + strlen(END_TAG);
                remaining -= (m - m0);
        }
 
-       fwrite(m, 1, size, stdout);
-       unmap_file(mp, size);
+       if (remaining > 0) {
+               fwrite(m, 1, remaining, stdout);
+       }
        fflush(stdout);
+       unmap_file(mp, size);
        return 0;
 }
 
index 8581a99..ad0ab57 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+typedef void (*template_fn)(struct template_state *, const char *, const char *,
+                           int, char **);
+
 struct template_var {
        struct template_var *next;
        char *name;
        char *value;
+       template_fn function;
 };
 
+
 struct template_state {
        /* methods */
        int (*process)(struct template_state *, const char *);
-       void (*put)(struct template_state *, const char *, const char *);
+       void (*put)(struct template_state *, const char *, const char *, template_fn fn);
        const char *(*get)(struct template_state *, const char *name);
        void (*destroy)(struct template_state *);
 
index 61e678d..3dffc1d 100644 (file)
@@ -1,70 +1,59 @@
 #include "includes.h"
 
-/* they have pressed "Install" */
-static void do_install(struct cgi_state *cgi)
+static struct cgi_state *cgi;
+
+/* this is a helper function for file upload. The scripts can call 
+  @save_file(cgi_variablename, filename) to save the contents of 
+  an uploaded file to disk
+*/
+static void save_file(struct template_state *tmpl, 
+                     const char *name, const char *value,
+                     int argc, char **argv)
 {
-       struct template_state *tmpl = cgi->tmpl;
+       char *var_name, *file_name;
+       int fd;
+       const char *content;
+       unsigned size, ret;
 
-       tmpl->put(tmpl, "install_script", "./installroot.sh");
-
-       cgi->setvar(cgi, "archive_location");
-       cgi->setvar(cgi, "proxy_server");
-
-       cgi->download(cgi, "install.html");
-}
-
-/* they have pressed "Upgrade" */
-static void do_upgrade(struct cgi_state *cgi)
-{
-       struct template_state *tmpl = cgi->tmpl;
-
-       tmpl->put(tmpl, "install_script", "./upgraderoot.sh");
-
-       cgi->setvar(cgi, "archive_location");
-       cgi->setvar(cgi, "proxy_server");
-
-       cgi->download(cgi, "install.html");
-}
-
-/* they have pressed "Diagnostics" */
-static void do_diagnostics(struct cgi_state *cgi)
-{
-       cgi->download(cgi, "diagnostics.html");
-}
+       if (argc != 2) {
+               printf("Invalid arguments to function %s (%d)\n", name, argc);
+               return;
+       }
+       var_name = argv[0];
+       file_name = argv[1];
 
-/* they have pressed "Diagnostics" */
-static void do_main_page(struct cgi_state *cgi)
-{
-       cgi->download(cgi, "index.html");
+       content = cgi->get_content(cgi, var_name, &size);
+       if (!content) {
+               printf("No content for variable %s?\n", var_name);
+               return;
+       }
+       fd = open(file_name, O_CREAT | O_TRUNC | O_WRONLY, 0644);
+       if (fd == -1) {
+               printf("Failed to open %s (%s)\n", file_name, strerror(errno));
+               return;
+       }
+       ret = write(fd, content, size);
+       if (ret != size) {
+               printf("out of space writing %s (wrote %u)\n", file_name, ret);
+       }
+       close(fd);
 }
 
 /* the main webserver process, called with stdin and stdout setup
  */
 static void run_webserver(void)
 {
-       struct cgi_state *cgi;
-       const char *action;
        struct stat st;
-       int i;
-       struct {
-               char *name;
-               void (*fn)(struct cgi_state *);
-       } actions[] = {
-               {"Install", do_install},
-               {"Upgrade", do_upgrade},
-               {"Diagnostics", do_diagnostics},
-               {NULL, do_main_page}
-       };
 
-       if (chdir("files") != 0) {
-               fprintf(stderr,"Can't find files directory?\n");
+       if (chdir("html") != 0) {
+               fprintf(stderr,"Can't find html directory?\n");
                exit(1);
        }
 
        cgi = cgi_init();
-
        cgi->setup(cgi);
        cgi->load_variables(cgi);
+       cgi->tmpl->put(cgi->tmpl, "save_file", "", save_file);
 
        /* handle a direct file download */
        if (!strstr(cgi->pathinfo, "..") && *cgi->pathinfo != '/' &&
@@ -74,15 +63,7 @@ static void run_webserver(void)
                return;
        }
 
-       action = cgi->get(cgi, "action");
-
-       for (i=0; actions[i].name; i++) {
-               if (action && fnmatch(actions[i].name, action, 0) == 0) break;
-       }
-       
-       /* call the action handler */
-       actions[i].fn(cgi);
-
+       cgi->download(cgi, "index.html");
        cgi->destroy(cgi);
 }
 
@@ -90,7 +71,19 @@ static void run_webserver(void)
 /* main program, just start listening and answering queries */
 int main(int argc, char *argv[])
 {
-       tcp_listener(TSERVER_PORT, TSERVER_LOGFILE, run_webserver);
+       int port = TSERVER_PORT;
+       extern char *optarg;
+       int opt;
+
+       while ((opt=getopt(argc, argv, "p:")) != -1) {
+               switch (opt) {
+               case 'p':
+                       port = atoi(optarg);
+                       break;
+               }
+       }       
+
+       tcp_listener(port, run_webserver);
        return 0;
 }
 
index 8809e1f..32c0b8b 100644 (file)
@@ -4,7 +4,7 @@
 listen on a tcp port then call fn() for each new connection with stdin and stdout
 set to the socket and stderr pointing at logfile
 ****************************************************************************/
-void tcp_listener(int port, const char *logfile, void (*fn)(void))
+void tcp_listener(int port, void (*fn)(void))
 {
        struct sockaddr_in sock;
        int res;
@@ -29,6 +29,8 @@ void tcp_listener(int port, const char *logfile, void (*fn)(void))
                if (fork() == 0) {
                        close(res);
                        /* setup stdin and stdout */
+                       fflush(stdout);
+                       fflush(stderr);
                        dup2(fd, 0);
                        dup2(fd, 1);
                        close(fd);
@@ -85,3 +87,14 @@ void *x_malloc(size_t size)
        }
        return ret;
 }
+
+
+/* 
+   trim the tail of a string
+*/
+void trim_tail(char *s, char *trim_chars)
+{
+       int len = strlen(s);
+       while (len > 0 && strchr(trim_chars, s[len-1])) len--;
+       s[len] = 0;
+}