Varie correzioni, completata revisione capitolo sull'I/O su file
[gapil.git] / sources / wwwd.c
index 3379486e08a431d0e8febd3f003632e369120537..0b6dfde9a9be2ca3e0ba4d2dcf04ee149e530083 100644 (file)
  *
  * Usage: wwwd -h give all info
  *
- * $Id$ 
- *
  ****************************************************************/
 /* 
  * Include needed headers
  */
 #define _GNU_SOURCE
-#include <string.h>      /* error strings */
-#include <sys/types.h>   /* predefined types */
-#include <unistd.h>      /* include unix standard library */
-#include <arpa/inet.h>   /* IP addresses conversion utiliites */
-#include <sys/socket.h>  /* socket library */
-#include <stdio.h>      /* include standard I/O library */
-#include <time.h>
+#include <sys/types.h>   /* primitive system data types */
+#include <sys/stat.h>    /* file characteristics constants and functions */
+#include <stdlib.h>      /* C standard library */
+#include <stdio.h>      /* standard I/O library */
+#include <unistd.h>      /* unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utilities */
+#include <sys/socket.h>  /* socket constants, types and functions */
+#include <time.h>        /* date and time constants, types and functions */
 #include <syslog.h>      /* syslog system functions */
-#include <signal.h>      /* signal functions */
-#include <errno.h>       /* error code */
-#include <stdlib.h>
+#include <signal.h>      /* signal constants, types and functions */
+#include <errno.h>       /* error definitions and routines */
+#include <string.h>      /* C strings library */
+#include <dirent.h>      /* directory operation constants and functions */
 
 #include "Gapil.h"
 
+/* 
+ * Function and globals definitions
+ */
 #define BACKLOG 10
 #define MAXLINE 256
 int demonize  = 1;  /* daemon use option: default is daemon */
 int debugging = 0;  /* debug info printing option: default is no debug */
+struct code_page {
+    char * code; 
+    char * name;
+    char * body;
+};
 
-/* Subroutines declaration */
 void usage(void);
 void ServPage(int sockfd);
 void PrintErr(char * error);
-void print_headers(FILE *file);
+void print_headers(FILE *file, struct code_page code);
+void print_error(FILE *file, struct code_page page, char * string);
 
-/* Program beginning */
-int main(int argc, char *argv[])
+/*
+ * Main program
+ */int main(int argc, char *argv[])
 {
-/* 
- * Variables definition  
- */
+    /* 
    * Variables definition  
    */
     int list_fd, conn_fd;
-    int waiting = 0;
     int compat = 0;
+    int reroot = 0;
+    int reuse = 1;
+    char * rootdir;
     pid_t pid;
     struct sockaddr_in cli_add;
     socklen_t len;
@@ -77,7 +88,7 @@ int main(int argc, char *argv[])
      */
     int i;
     opterr = 0;         /* don't want writing to stderr */
-    while ( (i = getopt(argc, argv, "hdicw:")) != -1) {
+    while ( (i = getopt(argc, argv, "hwdicr:")) != -1) {
        switch (i) {
        /* 
         * Handling options 
@@ -97,7 +108,11 @@ int main(int argc, char *argv[])
            debugging = 1;
            break;
        case 'w':
-           waiting = strtol(optarg, NULL, 10);
+           reuse = 0;
+           break;
+       case 'r':
+           reroot = 1;
+           rootdir = optarg;
            break;
        case '?':   /* unrecognized options */
            printf("Unrecognized options -%c\n",optopt);
@@ -120,9 +135,21 @@ int main(int argc, char *argv[])
        SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
     }
     /* create and bind socket */
-    if ( (list_fd = sockbind2(argv[optind], "www", 6, SOCK_STREAM)) < 0) {
+    if ( (list_fd = sockbindopt(argv[optind], "www", 6, 
+                               SOCK_STREAM, reuse)) < 0) {
        return 1;
     }   
+    /* chroot if requested */
+    if (reroot) {
+       if (chdir(rootdir)) {
+           perror("Cannot find directory to chroot");
+           exit(1);
+       }
+       if (chroot(rootdir)) {
+           perror("Cannot chroot");
+           exit(1);
+       }
+    }
     /* release privileges and go daemon */
     if (setgid(65534) !=0) { /* first give away group privileges */
        perror("cannot give away group privileges");
@@ -144,7 +171,6 @@ int main(int argc, char *argv[])
        PrintErr("listen error");
        exit(1);
     }
-    if (waiting) sleep(waiting);
     /* handle echo to client */
     while (1) {
        /* accept connection */
@@ -195,12 +221,12 @@ void usage(void)
 {
     printf("Elementary echo server\n");
     printf("Usage:\n");
-    printf("  echod [-h] \n");
+    printf("  wwwd [-h] \n");
     printf("  -h          print this help\n");
     printf("  -d          write debug info\n");
     printf("  -i          use interactively\n");
     printf("  -c          disable BSD semantics\n");
-    printf("  -w N        wait N sec. before calling accept\n");
+    printf("  -r /path    chroot on /path\n");
     exit(1);
 }
 /*
@@ -212,37 +238,46 @@ void ServPage(int sockfd)
     char outbuf[1024];
     FILE *sock, *file;
     char *line, *copy, *method, *ptr, *filename, *version;
-    char *methods[] = { "GET", "PUT", NULL };
-    char *codes[] = {
-       "200 OK",
-       "404 Not Found",
-       NULL
+    char *methods[] = { "GET", "HEAD", NULL };
+    struct code_page codes[] = {
+       { "200", "OK", "%s"},
+       { "400", "Bad Request", 
+          "Your browser sent a request that this server could not understand."
+         "<P>The request line<P>%s<P> is invalid following the protocol<P>"}, 
+       { "404", "Not Found", 
+          "The requested URL %s was not found on this server.<P>"},
+       { "500", "Internal Server Error", 
+          "We got an error processing your request.<P>Error is: %s<P>"},
+       { "405", "Method Not Allowed", "Method %s not allowed.<P>"},
+       { "403", "Forbidden", "You cannot access %s.<P>"}
     };
     int nleft;
-    int i, j;
+    int i;
 
     sock = fdopen(sockfd, "w+");
     /* main loop, reading 0 char means client close connection */
     line = fgets(buffer, MAXLINE, sock);
-    copy = strndupa(line, MAXLINE);
-
     if (line == NULL) {
        PrintErr("Errore in lettura");
        return;
     }
+    /* parsing first line, getting method and filename */
+    copy = strndupa(line, MAXLINE);
     if ((method = strtok_r(copy, " ", &ptr)) == NULL) {
-       PrintErr("Non ho trovato il metodo");
+       print_headers(sock, codes[1]);
+       print_error(sock, codes[1], line);
        return;
     }
     if ((filename = strtok_r(NULL, " ", &ptr)) == NULL) {
-       PrintErr("Non ho trovato il file");
+       print_headers(sock, codes[1]);
+       print_error(sock, codes[1], line);
        return;
     }
     if ((version = strtok_r(NULL, " ", &ptr)) == NULL) {
-       PrintErr("Non ho trovato la versione");
+       print_headers(sock, codes[1]);
+       print_error(sock, codes[1], line);
        return;
     }
-    printf("metodo %s -- file %s -- versione %s\n", method, filename, version);
     i = 0;
     while ( (ptr = methods[i]) != NULL) {
        if ( (strncmp(ptr, method, strlen(ptr)) == 0)) {
@@ -251,45 +286,44 @@ void ServPage(int sockfd)
        i++;
     }
     if (i>=2) {
-       printf("No method %s found\n", method);
+       print_headers(sock, codes[4]);
+       print_error(sock, codes[4], method);
        return;
     }
 
     while (strcmp(line,"\r\n")) {
-       line =  fgets(buffer, MAXLINE, sock);
-       printf("letto: %s\n", line);
+       line = fgets(buffer, MAXLINE, sock);
     }
 
     if ( (file = fopen(filename, "r")) == NULL) {
-       printf("file %s", filename);
-       perror("Error opening");
-       fprintf(sock, "HTTP/1.0 %s\n", codes[1]);
-       print_headers(sock);
+       if ( (errno == EACCES)||(errno == EPERM) ) {
+           print_headers(sock, codes[5]);
+           print_error(sock, codes[5], filename);
+       } else {
+           print_headers(sock, codes[2]);
+           print_error(sock, codes[2], filename);
+       }
        return;
     }
-    fprintf(sock, "HTTP/1.0 %s\n", codes[0]);
-    //PrintHeader(sock);
-    print_headers(sock);
-
-    j = 0;
+    print_headers(sock, codes[0]);
     while (!feof(file)) {
-       printf("Loop %d\n", j++);
        if ( (nleft = full_fread(file, outbuf, 1024)) != 0) {
            if (ferror(file)) {
-               printf("Errore in lettura");
+               strncpy(buffer, strerror(errno), MAXLINE);
+               print_headers(sock, codes[3]);
+               print_error(sock, codes[3], buffer);
                return;
            }
        }
-       printf("Loop %d rimasti %d\n", j, nleft);
        if (full_fwrite(sock, outbuf, 1024-nleft) != 0) {
            if (ferror(file)) {
-               printf("Errore in scrittura");
+               strncpy(buffer, strerror(errno), MAXLINE);
+               print_headers(sock, codes[3]);
+               print_error(sock, codes[3], buffer);
                return;
            }   
        }
     }
-    printf("Ok fin qui!");
-//    line = fgets(buffer, MAXLINE, sock);
     fclose(file);
     fclose(sock);
     return;
@@ -307,20 +341,27 @@ void PrintErr(char * error)
     return;
 }
 
-void print_headers(FILE *file)
+void print_headers(FILE *file, struct code_page code)
 {
     time_t tempo;
 
+    fprintf(file, "HTTP/1.0 %s %s \n", code.code, code.name);
     time(&tempo);
     fprintf(file, "Date: %s", ctime(&tempo));
     fprintf(file, "Server: WWWd test server\n");
     fprintf(file, "Connection: close\n");
     fprintf(file, "Content-Type: text/html; charset=iso-8859-1\n");
     fprintf(file, "\n");
-    printf("Date: %s", ctime(&tempo));
-    printf("Server: WWWd test server\n");
-    printf("Connection: close\n");
-    printf("Content-Type: text/html; charset=iso-8859-1\n");
-    printf("\n");
     return;
 }
+
+void print_error(FILE *file, struct code_page page, char * string)
+{
+    fprintf(file, "<HTML><HEAD><TITLE>%s %s</TITLE></HEAD>\n",
+           page.code, page.name);
+    fprintf(file, "<BODY><H1>%s</H1>\n", page.name);
+    fprintf(file, page.body, string);
+    fprintf(file, "<HR><ADDRESS>WWWd by S. Piccardi</ADDRESS></BODY></HTML>");
+    return;
+}
+