|
|
|
/* main.cpp
|
|
|
|
*
|
|
|
|
* Copyright (c) 1998-2000 Alexander Neundorf
|
|
|
|
* neundorf@kde.org
|
|
|
|
*
|
|
|
|
* You may distribute under the terms of the GNU General Public
|
|
|
|
* License as specified in the COPYING file.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "lisadefines.h"
|
|
|
|
#include "netmanager.h"
|
|
|
|
|
|
|
|
#ifdef LISA_DEBUG
|
|
|
|
#undef LISA_DEBUG
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef dcerr
|
|
|
|
#undef dcerr
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define LISA_DEBUG 0
|
|
|
|
#define dcerr if (LISA_DEBUG==1) std::cerr<<"main "
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
// detect linux/glibc for the gnu style --args
|
|
|
|
#if defined(__linux__) || defined(__linux) || defined(linux)
|
|
|
|
# include <features.h>
|
|
|
|
# ifdef __GLIBC__
|
|
|
|
// only gnu libc has getopt.h... getopt(3) is defined to be in unistd.h
|
|
|
|
// by POSIX.2
|
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
# define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
# include <getopt.h>
|
|
|
|
# endif // __GLIBC__
|
|
|
|
# define GNU_GETOPT
|
|
|
|
#endif // linux
|
|
|
|
|
|
|
|
|
|
|
|
void printVersion()
|
|
|
|
{
|
|
|
|
const char * versionInfo=\
|
|
|
|
"\r\nThis is the LAN Information Server LISa "MYVERSION"\r\n"\
|
|
|
|
"It is free software according the GNU General Public License\r\n"\
|
|
|
|
"Copyright (c) 2000-2003 by Alexander Neundorf\r\n"\
|
|
|
|
"email: neundorf@kde.org\r\n";
|
|
|
|
std::cout<<versionInfo<<std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void usage()
|
|
|
|
{
|
|
|
|
printVersion();
|
|
|
|
const char * usageInfo=\
|
|
|
|
"-v, --version prints out a short version info\n"\
|
|
|
|
"-u, --unix deprecated\n"\
|
|
|
|
"-k, --kde1 deprecated\n"\
|
|
|
|
"-K, --kde2 deprecated\n"\
|
|
|
|
" lisa now looks always first for $(HOME)/.lisarc, then for /etc/lisarc\n"\
|
|
|
|
"-c, --config=FILE read this and no other configuration file\n"\
|
|
|
|
"-q, --quiet start quiet without the greeting message\n"\
|
|
|
|
"-p, --port PORTNR start the server on this portnumber\n"\
|
|
|
|
" if you use this LISa won't be able to\n"\
|
|
|
|
" cooperate with other LISa's in the network\n"\
|
|
|
|
"-h, --help you are currently reading it ;-)\n";
|
|
|
|
std::cout<<usageInfo<<std::endl;
|
|
|
|
//I thought this would be the way to check wether long options are supported...
|
|
|
|
//#ifndef _GNU_SOURCE
|
|
|
|
// std::cout<<"Please note that the long options are not supported on
|
|
|
|
// this system"<<std::endl;
|
|
|
|
//#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
NetManager *manager(0);
|
|
|
|
|
|
|
|
|
|
|
|
void destruct(int sigNumber)
|
|
|
|
{
|
|
|
|
signal(sigNumber,SIG_IGN);
|
|
|
|
dcerr<<"signal caught: "<<sigNumber<<", exiting"<<std::endl;
|
|
|
|
//signal(sigNumber,&destruct);
|
|
|
|
if (manager!=0)
|
|
|
|
manager->~NetManager();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void readConfig(int sigNumber)
|
|
|
|
{
|
|
|
|
dcerr<<"readConfig(): signal caught: "<<sigNumber<<std::endl;
|
|
|
|
signal(SIGHUP,SIG_IGN);
|
|
|
|
if (manager!=0)
|
|
|
|
manager->readConfig();
|
|
|
|
signal(SIGHUP,&readConfig);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printState(int sigNumber)
|
|
|
|
{
|
|
|
|
dcerr<<"printState(): signal caught: "<<sigNumber<<std::endl;
|
|
|
|
signal(SIGUSR1,SIG_IGN);
|
|
|
|
if (manager!=0)
|
|
|
|
manager->printState();
|
|
|
|
signal(SIGUSR1,&printState);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setSignalHandler()
|
|
|
|
{
|
|
|
|
signal(SIGHUP,&readConfig);
|
|
|
|
signal(SIGUSR1,&printState);
|
|
|
|
|
|
|
|
signal(SIGINT,&destruct);
|
|
|
|
signal(SIGQUIT,&destruct);
|
|
|
|
signal(SIGILL,&destruct);
|
|
|
|
signal(SIGTRAP,&destruct);
|
|
|
|
signal(SIGABRT,&destruct);
|
|
|
|
signal(SIGBUS,&destruct);
|
|
|
|
signal(SIGSEGV,&destruct);
|
|
|
|
signal(SIGUSR2,&destruct);
|
|
|
|
signal(SIGPIPE,&destruct);
|
|
|
|
signal(SIGALRM,&destruct);
|
|
|
|
signal(SIGTERM,&destruct);
|
|
|
|
signal(SIGFPE,&destruct);
|
|
|
|
#ifdef SIGPOLL
|
|
|
|
signal(SIGPOLL, &destruct);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGSYS
|
|
|
|
signal(SIGSYS, &destruct);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGVTALRM
|
|
|
|
signal(SIGVTALRM, &destruct);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGXCPU
|
|
|
|
signal(SIGXCPU, &destruct);
|
|
|
|
#endif
|
|
|
|
#ifdef SIGXFSZ
|
|
|
|
signal(SIGXFSZ, &destruct);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef GNU_GETOPT
|
|
|
|
static struct option const long_opts[] =
|
|
|
|
{
|
|
|
|
{"version", no_argument, 0, 'v'},
|
|
|
|
{"quiet", no_argument, 0, 'q'},
|
|
|
|
{"unix", no_argument, 0, 'u'},
|
|
|
|
{"kde1", no_argument, 0, 'k'},
|
|
|
|
{"kde2", no_argument, 0, 'K'},
|
|
|
|
{"config", required_argument, 0, 'c'},
|
|
|
|
{"port", required_argument, 0, 'p'},
|
|
|
|
{"help", no_argument, 0, 'h'},
|
|
|
|
{0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
|
|
|
int quiet(0);
|
|
|
|
int c(0);
|
|
|
|
int configStyle(UNIXCONFIGSTYLE);
|
|
|
|
MyString configFile;
|
|
|
|
int portToUse(MYPORT);
|
|
|
|
|
|
|
|
//I thought this would be the way to check wether long options are supported...
|
|
|
|
#ifdef GNU_GETOPT
|
|
|
|
while ((c=getopt_long(argc, argv, "vqukKc:h", long_opts, 0))!=-1)
|
|
|
|
#else
|
|
|
|
while ((c=getopt(argc, argv, "vqukKc:h"))!=-1)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
{
|
|
|
|
char *endp(0);
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
printVersion();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
quiet=1;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
case 'k':
|
|
|
|
case 'K':
|
|
|
|
std::cout<<"\a\nThe command line switches -k, -K, -u and \ntheir long versions "\
|
|
|
|
"--kde1, --kde2 and --unix are not supported anymore.\n"\
|
|
|
|
"Lisa will always first look for $(HOME)/.lisarc , then for /etc/lisarc.\n"\
|
|
|
|
"If your lisa configuration file was created using an older version of \n"\
|
|
|
|
"the KDE control center, copy the /root/.kde/share/config/lisarc to /etc and \n"\
|
|
|
|
"then start lisa without any command line options.\n"<<std::endl;
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'c':
|
|
|
|
configFile = optarg;
|
|
|
|
configStyle = EXTRACONFIGSTYLE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'p':
|
|
|
|
portToUse=strtol(optarg,&endp,10);
|
|
|
|
if (endp!=0)
|
|
|
|
{
|
|
|
|
usage();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//fork and let the parent exit
|
|
|
|
pid_t pid=fork();
|
|
|
|
if (pid>0)
|
|
|
|
{
|
|
|
|
//this is the parent
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
else if (pid<0)
|
|
|
|
{
|
|
|
|
std::cout<<"could not fork()"<<std::endl;
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
//we will only read/write to/from this socket in the child process
|
|
|
|
int rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
|
|
|
|
if (rawSocket==-1)
|
|
|
|
{
|
|
|
|
std::cout<<"could not create raw socket, root privileges required"<<std::endl;
|
|
|
|
std::cout<<"take a look at the README for more information"<<std::endl;
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
int bufferSize(60*1024);
|
|
|
|
int on(1);
|
|
|
|
setsockopt(rawSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bufferSize,
|
|
|
|
sizeof(bufferSize));
|
|
|
|
int result=setsockopt(rawSocket, SOL_SOCKET, SO_BROADCAST, (char*)&on,
|
|
|
|
sizeof(on));
|
|
|
|
dcerr<<"setsockopt returns "<<result<<std::endl;
|
|
|
|
//dropping root privileges
|
|
|
|
//they will be regained once in the child process
|
|
|
|
//for creating a raw socket
|
|
|
|
|
|
|
|
//now dropping root privileges once and ever
|
|
|
|
|
|
|
|
|
|
|
|
setuid(getuid());
|
|
|
|
if (geteuid() != getuid())
|
|
|
|
_exit(255);
|
|
|
|
|
|
|
|
//according to R. Stevens the following three lines
|
|
|
|
//make daemons feel good :)
|
|
|
|
setsid();
|
|
|
|
chdir("/");
|
|
|
|
umask(0);
|
|
|
|
|
|
|
|
dcerr<<"starting, dropped root privileges"<<std::endl;
|
|
|
|
dcerr<<"port: "<<portToUse<<" file: "<<configFile<<std::endl;
|
|
|
|
NetManager netmanager(rawSocket,portToUse,configFile,configStyle,0);
|
|
|
|
manager=&netmanager;
|
|
|
|
dcerr<<"NetManager created"<<std::endl;
|
|
|
|
setSignalHandler();
|
|
|
|
|
|
|
|
netmanager.readConfig();
|
|
|
|
if (netmanager.prepare())
|
|
|
|
{
|
|
|
|
if (!quiet)
|
|
|
|
{
|
|
|
|
printVersion();
|
|
|
|
std::cout<<"\n\rrunning on port "<<portToUse<<"\n\rHave fun ! :-)"<<std::endl;
|
|
|
|
}
|
|
|
|
netmanager.run();
|
|
|
|
};
|
|
|
|
dcerr<<"server finished"<<std::endl;
|
|
|
|
}
|