wwwoffled.c
上传用户:seven77cht
上传日期:2007-01-04
资源大小:486k
文件大小:15k
- /***************************************
- $Header: /home/amb/wwwoffle/RCS/wwwoffled.c 2.20 1999/12/28 20:05:14 amb Exp $
- WWWOFFLE - World Wide Web Offline Explorer - Version 2.5d.
- A demon program to maintain the database and spawn the servers.
- ******************/ /******************
- Written by Andrew M. Bishop
- This file Copyright 1996,97,98,99 Andrew M. Bishop
- It may be distributed under the GNU Public License, version 2, or
- any higher version. See section COPYING of the GNU Public license
- for conditions under which this file may be redistributed.
- ***************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <sys/wait.h>
- #include <sys/time.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <errno.h>
- #include <signal.h>
- #include <grp.h>
- #include "version.h"
- #include "wwwoffle.h"
- #include "misc.h"
- #include "config.h"
- #include "sockets.h"
- #include "errors.h"
- #if defined (hpux)
- /* HP/UX has no `seteuid'. Instead it uses `setresuid' to set `uid', `euid', and `suid' simultaneously. */
- #define setegid(egid) setresgid (-1, (egid), -1)
- #define seteuid(euid) setresuid (-1, (euid), -1)
- #endif
- static void usage(int verbose);
- static void demoninit(void);
- static void install_sighandlers(void);
- static void sigchild(int signum);
- static void sigexit(int signum);
- static void sighup(int signum);
- /*+ The server sockets that we listen on +*/
- int http_fd=-1, /*+ for the HTTP connections. +*/
- wwwoffle_fd=-1; /*+ for the WWWOFFLE connections. +*/
- /*+ The online / offline /autodial status. +*/
- int online=0;
- /*+ The current number active servers +*/
- int n_servers=0, /*+ in total. +*/
- n_fetch_servers=0; /*+ fetching a page. +*/
- /*+ The wwwoffle client file descriptor when fetching. +*/
- int fetch_fd=-1;
- /*+ The pids of the servers. +*/
- int server_pids[MAX_SERVERS];
- /*+ The pids of the servers that are fetching. +*/
- int fetch_pids[MAX_FETCH_SERVERS];
- /*+ The current status, fetching or not. +*/
- int fetching=0;
- /*+ Set to 1 when the demon is to shutdown. +*/
- static int closedown=0;
- /*+ Set to 1 when the demon is to re-read config file due to a sighup. +*/
- static int readconfig=0;
- /*+ Remember that we got a SIGCHLD +*/
- static sig_atomic_t got_sigchld=0;
- /*+ True if run as a demon +*/
- static int detached=1;
- /*+ True if the pid of the daemon should be printed at startup +*/
- static int print_pid=0;
- /*++++++++++++++++++++++++++++++++++++++
- The main program.
- ++++++++++++++++++++++++++++++++++++++*/
- int main(int argc, char** argv)
- {
- int i;
- int err;
- struct stat buf;
- /* Parse the command line options */
- for(i=1;i<argc;i++)
- {
- if(!strcmp(argv[i],"-h"))
- usage(1);
- if(!strcmp(argv[i],"-d"))
- {
- detached=0;
- if(i<(argc-1) && isdigit(argv[i+1][0]) && !argv[i+1][1])
- {
- DebugLevel=Fatal+1-atoi(argv[++i]);
- if(DebugLevel<0)
- DebugLevel=0;
- }
- continue;
- }
- if(!strcmp(argv[i],"-p"))
- {
- print_pid=1;
- continue;
- }
- if(!strcmp(argv[i],"-c"))
- {
- if(++i>=argc)
- {fprintf(stderr,"wwwoffled: The '-c' option requires a filename.n"); exit(1);}
- ConfigFile=argv[i];
- continue;
- }
- fprintf(stderr,"wwwoffled: Unknown option '%s'.n",argv[i]); exit(1);
- }
- /* Initialise things. */
- for(i=0;i<MAX_FETCH_SERVERS;i++)
- fetch_pids[i]=0;
- for(i=0;i<MAX_SERVERS;i++)
- server_pids[i]=0;
- InitErrorHandler("wwwoffled",1,!detached);
- if(ReadConfigFile(2))
- PrintMessage(Fatal,"Error in configuration file '%s'.",ConfigFile);
- PrintMessage(Important,"WWWOFFLE Demon Version %s started.",WWWOFFLE_VERSION);
- PrintMessage(Inform,"WWWOFFLE Read Configuration File.");
- if(WWWOFFLE_Gid != -1)
- {
- if(getuid()==0)
- if(setgroups(0, NULL)<0)
- PrintMessage(Fatal,"Cannot clear supplementary group list [%!s].");
- if(setgid(WWWOFFLE_Gid)<0)
- PrintMessage(Fatal,"Cannot set group id to %d [%!s].",WWWOFFLE_Gid);
- if(setegid(WWWOFFLE_Gid)<0)
- PrintMessage(Fatal,"Cannot set effective group id to %d [%!s].",WWWOFFLE_Gid);
- }
- if(WWWOFFLE_Uid != -1)
- {
- if(setuid(WWWOFFLE_Uid)<0)
- PrintMessage(Fatal,"Cannot set user id to %d [%!s].",WWWOFFLE_Uid);
- if(seteuid(WWWOFFLE_Uid)<0)
- PrintMessage(Fatal,"Cannot set effective user id to %d [%!s].",WWWOFFLE_Uid);
- }
- if(WWWOFFLE_Gid != -1 || WWWOFFLE_Uid != -1)
- PrintMessage(Inform,"Running with uid=%d, gid=%d.",getuid(),getgid());
- http_fd=OpenServerSocket(HTTP_Port);
- if(http_fd==-1)
- PrintMessage(Fatal,"Cannot create HTTP server socket.");
- wwwoffle_fd=OpenServerSocket(WWWOFFLE_Port);
- if(wwwoffle_fd==-1)
- PrintMessage(Fatal,"Cannot create WWWOFFLE server socket.");
- umask(0);
- if(stat(SpoolDir,&buf))
- {
- err=mkdir(SpoolDir,DirPerm);
- if(err==-1 && errno!=EEXIST)
- PrintMessage(Fatal,"Cannot create spool directory %s [%!s].",SpoolDir);
- stat(SpoolDir,&buf);
- }
- if(!S_ISDIR(buf.st_mode))
- PrintMessage(Fatal,"The spool directory %s is not a directory.",SpoolDir);
- err=chdir(SpoolDir);
- if(err==-1)
- PrintMessage(Fatal,"Cannot change to spool directory %s [%!s].",SpoolDir);
- if(detached)
- {
- demoninit();
- PrintMessage(Important,"Detached from terminal and changed pid to %d.",getpid());
- InitErrorHandler("wwwoffled",1,!detached); /* pid changes after detaching. */
- }
- install_sighandlers();
- /* Loop around waiting for connections. */
- do
- {
- struct timeval tv;
- fd_set readfd;
- int nfds;
- int retval;
- if(http_fd>wwwoffle_fd)
- nfds=http_fd+1;
- else
- nfds=wwwoffle_fd+1;
- FD_ZERO(&readfd);
- FD_SET(wwwoffle_fd,&readfd);
- if(n_servers<MaxServers)
- FD_SET(http_fd,&readfd);
- tv.tv_sec=10;
- tv.tv_usec=0;
- retval=select(nfds,&readfd,NULL,NULL,&tv);
- if(retval!=-1)
- {
- if(FD_ISSET(wwwoffle_fd,&readfd))
- {
- char *host,*ip;
- int port,client;
- client=AcceptConnect(wwwoffle_fd);
- init_buffer(client);
- if(client>=0 && !SocketRemoteName(client,&host,&ip,&port))
- {
- if(IsAllowedConnectHost(host) || IsAllowedConnectHost(ip))
- {
- PrintMessage(Important,"WWWOFFLE Connection from host %s (%s).",host,ip); /* Used in audit-usage.pl */
- CommandConnect(client);
- if(fetch_fd!=client)
- CloseSocket(client);
- }
- else
- {
- PrintMessage(Warning,"WWWOFFLE Connection rejected from host %s (%s).",host,ip); /* Used in audit-usage.pl */
- CloseSocket(client);
- }
- }
- }
- if(FD_ISSET(http_fd,&readfd))
- {
- char *host,*ip;
- int port,client;
- client=AcceptConnect(http_fd);
- init_buffer(client);
- if(client>=0 && !SocketRemoteName(client,&host,&ip,&port))
- {
- if(IsAllowedConnectHost(host) || IsAllowedConnectHost(ip))
- {
- PrintMessage(Inform,"HTTP Proxy connection from host %s (%s).",host,ip); /* Used in audit-usage.pl */
- ForkServer(client,1);
- }
- else
- PrintMessage(Warning,"HTTP Proxy connection rejected from host %s (%s).",host,ip); /* Used in audit-usage.pl */
- CloseSocket(client);
- }
- }
- }
- if(readconfig)
- {
- readconfig=0;
- PrintMessage(Important,"SIGHUP signalled.");
- PrintMessage(Important,"WWWOFFLE Re-reading Configuration File.");
- if(ReadConfigFile(-1))
- PrintMessage(Warning,"Error in configuration file; keeping old values.");
- PrintMessage(Important,"WWWOFFLE Finished Re-reading Configuration File.");
- }
- if(got_sigchld)
- {
- int pid, status;
- int isserver=0;
- /* To avoid race conditions, reset the flag before fetching the status */
- got_sigchld=0;
- while((pid=waitpid(-1,&status,WNOHANG))>0)
- {
- int i;
- int exitval=0;
- if(WIFEXITED(status))
- exitval=WEXITSTATUS(status);
- else if(WIFSIGNALED(status))
- exitval=-WTERMSIG(status);
- for(i=0;i<MaxServers;i++)
- if(server_pids[i]==pid)
- {
- n_servers--;
- server_pids[i]=0;
- isserver=1;
- if(exitval>=0)
- PrintMessage(Inform,"Child wwwoffles exited with status %d (pid=%d).",exitval,pid);
- else
- PrintMessage(Important,"Child wwwoffles terminated by signal %d (pid=%d).",-exitval,pid);
- break;
- }
- /* Check if the child that terminated is one of the fetching wwwoffles */
- for(i=0;i<MaxFetchServers;i++)
- if(fetch_pids[i]==pid)
- {
- n_fetch_servers--;
- fetch_pids[i]=0;
- break;
- }
- if(exitval==3)
- fetching=0;
- if(exitval==4 && online==1)
- fetching=1;
- if(online!=1)
- fetching=0;
- }
- if(isserver)
- PrintMessage(Debug,"Currently running: %d servers total, %d fetchers.",n_servers,n_fetch_servers);
- }
- /* The select timed out or we got a signal. If we are currently fetching,
- start fetch servers to look for jobs in the spool directory. */
- while(fetching && n_fetch_servers<MaxFetchServers && n_servers<MaxServers)
- ForkServer(fetch_fd,0);
- if(fetch_fd!=-1 && !fetching && n_fetch_servers==0)
- {
- write_string(fetch_fd,"WWWOFFLE No more to fetch.n");
- CloseSocket(fetch_fd);
- fetch_fd=-1;
- PrintMessage(Important,"WWWOFFLE Fetch finished.");
- }
- }
- while(!closedown);
- /* Close down and exit. */
- CloseSocket(http_fd);
- CloseSocket(wwwoffle_fd);
- if(n_servers)
- PrintMessage(Important,"Exit signalled - waiting for %d child wwwoffles servers.",n_servers);
- else
- PrintMessage(Important,"Exit signalled.");
- while(n_servers)
- {
- int i;
- int pid,status,exitval=0;
- while((pid=waitpid(-1,&status,0))>0)
- {
- if(WIFEXITED(status))
- exitval=WEXITSTATUS(status);
- else if(WIFSIGNALED(status))
- exitval=-WTERMSIG(status);
- for(i=0;i<MaxServers;i++)
- if(server_pids[i]==pid)
- {
- n_servers--;
- server_pids[i]=0;
- if(exitval>=0)
- PrintMessage(Inform,"Child wwwoffles exited with status %d (pid=%d).",exitval,pid);
- else
- PrintMessage(Important,"Child wwwoffles terminated by signal %d (pid=%d).",-exitval,pid);
- break;
- }
- }
- }
- PrintMessage(Important,"Exiting.");
- return(0);
- }
- /*++++++++++++++++++++++++++++++++++++++
- Print the program usage in long or short format.
- int verbose True for long format.
- ++++++++++++++++++++++++++++++++++++++*/
- static void usage(int verbose)
- {
- fprintf(stderr,
- "n"
- "WWWOFFLED - World Wide Web Offline Explorer (Demon) - Version %sn"
- "n",WWWOFFLE_VERSION);
- if(verbose)
- fprintf(stderr,
- "(c) Andrew M. Bishop 1996,97,98 [ amb@gedanken.demon.co.uk ]n"
- " [http://www.gedanken.demon.co.uk/]n"
- "n");
- fprintf(stderr,
- "Usage: wwwoffled [-h] [-c <config-file>] [-d [<log-level>]]n"
- "n");
- if(verbose)
- fprintf(stderr,
- " -h : Display this help.n"
- "n"
- " -c <config-file> : The name of the configuration file to use.n"
- " (Default %s).n"
- "n"
- " -d [<log-level>] : Do not detach from the terminal and use stderr.n"
- " 0 <= log-level <= %d (default in config file).n"
- "n"
- " -p : Print the pid of wwwoffled on stdout (unless -d).n"
- "n",ConfigFile,Fatal+1);
- exit(0);
- }
- /*++++++++++++++++++++++++++++++++++++++
- Detach ourself from the controlling terminal.
- ++++++++++++++++++++++++++++++++++++++*/
- static void demoninit(void)
- {
- pid_t pid=0;
- pid=fork();
- if(pid==-1)
- PrintMessage(Fatal,"Cannot fork() to detach(1) [%!s].");
- else if(pid)
- exit(0);
- setsid();
- pid=fork();
- if(pid==-1)
- PrintMessage(Fatal,"Cannot fork() to detach(2) [%!s].");
- else if(pid)
- {
- /* print the child pid on stdout as requested */
- if(print_pid)
- printf("%dn", pid);
- exit(0);
- }
- /* Close fds */
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- }
- /*++++++++++++++++++++++++++++++++++++++
- Install the signal handlers.
- ++++++++++++++++++++++++++++++++++++++*/
- static void install_sighandlers(void)
- {
- struct sigaction action;
- /* SIGCHLD */
- action.sa_handler = sigchild;
- sigemptyset (&action.sa_mask);
- action.sa_flags = 0;
- if(sigaction(SIGCHLD, &action, NULL) != 0)
- PrintMessage(Warning, "Cannot install SIGCHLD handler.");
- /* SIGINT, SIGQUIT, SIGTERM */
- action.sa_handler = sigexit;
- sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGINT); /* Block all of them */
- sigaddset(&action.sa_mask, SIGQUIT);
- sigaddset(&action.sa_mask, SIGTERM);
- action.sa_flags = 0;
- if(sigaction(SIGINT, &action, NULL) != 0)
- PrintMessage(Warning, "Cannot install SIGINT handler.");
- if(sigaction(SIGQUIT, &action, NULL) != 0)
- PrintMessage(Warning, "Cannot install SIGQUIT handler.");
- if(sigaction(SIGTERM, &action, NULL) != 0)
- PrintMessage(Warning, "Cannot install SIGTERM handler.");
- /* SIGHUP */
- action.sa_handler = sighup;
- sigemptyset(&action.sa_mask);
- action.sa_flags = 0;
- if(sigaction(SIGHUP, &action, NULL) != 0)
- PrintMessage(Warning, "Cannot install SIGHUP handler.");
- /* SIGPIPE */
- action.sa_handler = SIG_IGN;
- sigemptyset (&action.sa_mask);
- action.sa_flags = 0;
- if(sigaction(SIGPIPE, &action, NULL) != 0)
- PrintMessage(Warning, "Cannot ignore SIGPIPE.");
- }
- /*++++++++++++++++++++++++++++++++++++++
- The signal handler for the child exiting.
- int signum The signal number.
- ++++++++++++++++++++++++++++++++++++++*/
- static void sigchild(int signum)
- {
- got_sigchld=1;
- }
- /*++++++++++++++++++++++++++++++++++++++
- The signal handler for the signals to tell us to exit.
- int signum The signal number.
- ++++++++++++++++++++++++++++++++++++++*/
- static void sigexit(int signum)
- {
- closedown=1;
- }
- /*++++++++++++++++++++++++++++++++++++++
- The signal handler for the signals to tell us to re-read the config file.
- int signum The signal number.
- ++++++++++++++++++++++++++++++++++++++*/
- static void sighup(int signum)
- {
- readconfig=1;
- }