main.c++
上传用户:weiyuanprp
上传日期:2020-05-20
资源大小:1169k
文件大小:10k
源码类别:

传真(Fax)编程

开发平台:

C/C++

  1. /* $Id: main.c++,v 1.6 2009/09/29 11:10:13 faxguy Exp $ */
  2. /*
  3.  * Copyright (c) 1995-1996 Sam Leffler
  4.  * Copyright (c) 1995-1996 Silicon Graphics, Inc.
  5.  * HylaFAX is a trademark of Silicon Graphics
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include "port.h"
  27. #include "InetFaxServer.h"
  28. #if CONFIG_UNIXTRANSPORT
  29. #include "UnixFaxServer.h"
  30. #endif
  31. #ifdef SNPP_SUPPORT
  32. #include "SNPPServer.h"
  33. #endif
  34. #ifdef HTTP_SUPPORT
  35. #include "HTTPServer.h"
  36. #endif
  37. #include "Dispatcher.h"
  38. #include "Array.h"
  39. #include "Sys.h"
  40. #include "Socket.h"
  41. #include "config.h"
  42. static jmp_buf problem;
  43. static void
  44. sigCleanup(int sig)
  45. {
  46.     logError("CAUGHT SIGNAL %d", sig);
  47.     longjmp(problem, 1);
  48. }
  49. static void
  50. fatal(const char* fmt ...)
  51. {
  52.     va_list ap;
  53.     va_start(ap, fmt);
  54.     vlogError(fmt, ap);
  55.     va_end(ap);
  56.     exit(-1);
  57. }
  58. #define PATH_DEVNULL "dev/null"
  59. #define PATH_DEVTCP "dev/tcp"
  60. #define PATH_NETCONFIG "etc/netconfig"
  61. #define PATH_DEVSOCKSYS "dev/socksys"
  62. /*
  63.  * Verify and possibly setup the chroot'd filesystem as
  64.  * required by the system.  Specifically, create a private
  65.  * copy of /dev/null and any networking-related files
  66.  * required by SVR4-based TCP/IP support.  We do this work
  67.  * because the process runs chroot'd to the top of the
  68.  * spooling area so normal files in the root filesystem
  69.  * are inaccessible.
  70.  *
  71.  * NB: This work could be done once in a setup script but
  72.  *     creating duplicates of character special device files
  73.  *     is not simple from the shell.
  74.  */
  75. static void
  76. CheckSpoolingSetup(void)
  77. {
  78.     struct stat sb;
  79.     uid_t ouid = geteuid();
  80.     (void) seteuid(0);
  81.     mode_t omask = umask(0);
  82.     /*
  83.      * Craft a private /dev/null in the chroot'd filesystem
  84.      * for use by syslog because some syslogs require this
  85.      * to function correctly.
  86.      */
  87.     if (!Sys::isCharSpecialFile(PATH_DEVNULL)) {
  88. if (!Sys::isCharSpecialFile("/" PATH_DEVNULL, sb))
  89.     fatal("stat(%s): %s", "/" PATH_DEVNULL, strerror(errno));
  90. if (mknod(PATH_DEVNULL, sb.st_mode, sb.st_rdev) < 0)
  91.     fatal("Could not create %s: %s", PATH_DEVNULL, strerror(errno));
  92.     }
  93.     /*
  94.      * If the system appears to support SVR4-style TCP/IP
  95.      * support then craft a private copy of the necessary
  96.      * files so that socket-related calls can be made after
  97.      * chroot'ing to the top of the spooling area.
  98.      *
  99.      * NB: It is assumed that the dev subdirectory is already
  100.      *     present (make install or similar should create it).
  101.      */
  102.     if (Sys::isCharSpecialFile("/" PATH_DEVTCP, sb) &&
  103.       !Sys::isCharSpecialFile(PATH_DEVTCP)) {
  104. if (mknod(PATH_DEVTCP, sb.st_mode, sb.st_rdev) < 0)
  105.     fatal("Could not create %s: %s", PATH_DEVTCP, strerror(errno));
  106. /*
  107.  * Copy /etc/netconfig if not already present.
  108.  */
  109. if (Sys::stat(PATH_NETCONFIG, sb) < 0) {
  110.     int src = Sys::open("/" PATH_NETCONFIG, O_RDONLY);
  111.     if (src >= 0) {
  112. int dst = Sys::open(PATH_NETCONFIG, O_WRONLY|O_CREAT, 0444);
  113. if (dst < 0)
  114.     fatal("creat(%s): %s", PATH_NETCONFIG, strerror(errno));
  115. char buf[4096];
  116. int cc;
  117. while ((cc = read(src, buf, sizeof (buf))) > 0)
  118.     if (write(dst, buf, cc) < 0)
  119. fatal("write(%s): %s", PATH_NETCONFIG, strerror(errno));
  120. close(dst);
  121. close(src);
  122.     } else
  123. logWarning("%s: Cannot open: %s",
  124.     "/" PATH_NETCONFIG, strerror(errno));
  125. }
  126.     }
  127.     /*
  128.      * SCO OS 5 apparently needs a /dev/socksys to implement
  129.      * setsockopt calls (sigh); create one in the chroot'd
  130.      * area if one exists in the root filesystem.
  131.      */
  132.     if (Sys::isCharSpecialFile("/" PATH_DEVSOCKSYS, sb) &&
  133.       !Sys::isCharSpecialFile(PATH_DEVSOCKSYS))
  134. if (mknod(PATH_DEVSOCKSYS, sb.st_mode, sb.st_rdev) < 0)
  135.     fatal("Could not create %s: %s", PATH_DEVSOCKSYS, strerror(errno));
  136.     (void) umask(omask);
  137.     seteuid(ouid);
  138. }
  139. /*
  140.  * Break the association with the controlling tty.
  141.  * Note that we do not close all the open file descriptors
  142.  * because many systems cache open descriptors within libraries
  143.  * for performance reasons and do not react well when you close
  144.  * them w/o telling them about it (and some don't react well
  145.  * even when you *DO* tell them).  Since we know we're called
  146.  * very early on from main in all our apps we just assume that
  147.  * we only need to remove the stdin+stdout+stderr before forking
  148.  * and starting a new session.
  149.  */
  150. static void
  151. detachFromTTY(void)
  152. {
  153.     int fd = Sys::open(_PATH_DEVNULL, O_RDWR);
  154.     if (fd == -1)
  155. fatal("Could not open null device file %s.", _PATH_DEVNULL);
  156.     dup2(fd, STDIN_FILENO);
  157.     dup2(fd, STDOUT_FILENO);
  158.     dup2(fd, STDERR_FILENO);
  159.     Sys::close(fd);
  160.     switch (fork()) {
  161.     case 0: break; // child, continue
  162.     case -1: _exit(1); // error
  163.     default: _exit(0); // parent, terminate
  164.     }
  165.     (void) setsid();
  166. }
  167. static void
  168. usage(const char* appName)
  169. {
  170.     fatal("usage: %s [-d] [-o port] [-O] [-f bindaddressfamily] [-h port] [-H] [-l bindaddress] [-i port] [-I] [-s port] [-S] [-u socket] [-q queue-directory]",
  171. appName);
  172. }
  173. fxDECLARE_PtrArray(IOHandlerArray, IOHandler*)
  174. fxIMPLEMENT_PtrArray(IOHandlerArray, IOHandler*)
  175. static IOHandlerArray handlers;
  176. static void
  177. newInetServer(void)
  178. {
  179.     InetFaxServer* server = new InetFaxServer;
  180.     server->open();
  181.     handlers.append(server);
  182. }
  183. int
  184. main(int argc, char** argv, char** envp)
  185. {
  186.     const char *bindaddress = NULL;
  187.     const char *addressfamily = NULL;
  188.     HylaFAXServer::setLogFacility(LOG_FAX);
  189.     HylaFAXServer::setupLogging("HylaFAX");
  190.     HylaFAXServer::setupPermissions();
  191.     fxStr appName = argv[0];
  192.     u_int l = appName.length();
  193.     appName = appName.tokenR(l, '/');
  194.     optind = 1;
  195.     opterr = 0;
  196.     int c;
  197.     const char* opts = "c:dD:f:Hh:Ii:Oo:q:Ss:u:l:";
  198.     /*
  199.      * Deduce the spooling directory and whether or not to
  200.      * detach the process from the controlling tty.  The
  201.      * latter is complicated by the fact that we run both
  202.      * as a master-server process and as a subprocess to
  203.      * inetd.  If we are to act as a master-server then we
  204.      * detach by default.  If we are invoked by inetd then
  205.      * do not detach.  If no arguments are specified then
  206.      * we imply a -I option (the new fax protocol) and do
  207.      * not want to detach.  The logic is a touch convoluted
  208.      * to do this correctly and is probably not worth the
  209.      * effort (except to reduce configuration errors).
  210.      */
  211.     fxStr queueDir(FAX_SPOOLDIR);
  212.     int detach = -1; // unknown state
  213.     while ((c = Sys::getopt(argc, argv, opts)) != -1)
  214. switch (c) {
  215. case 'c':
  216.     HylaFAXServer::configOptions.append(optarg);
  217.     break;
  218. case 'f': case 'h': case 'i': case 'o': case 's': case 'u':
  219.     if (detach == -1) // detach unless explicitly specified
  220. detach = true;
  221.     break;
  222. case 'H': case 'I': case 'O': case 'S':
  223.     if (detach == -1) // don't detach when invoked by inetd
  224. detach = false;
  225.     break;
  226. case 'd': detach = false; break;
  227. case 'D': HylaFAXServer::_debugSleep = atoi(optarg); break;
  228. case 'q': queueDir = optarg; break;
  229. case '?': usage(appName);
  230. }
  231.     if (detach == -1) // no protocol options means -I
  232. detach = false;
  233.     if (Sys::chdir(queueDir) < 0)
  234. fatal("Can not change directory to %s", (const char*)queueDir);
  235.     CheckSpoolingSetup();
  236.     if (detach)
  237. detachFromTTY();
  238.     /*
  239.      * Rescan the arguments and create the appropriate
  240.      * protocol support threads.  We do this after the
  241.      * above work for reasons I can no longer remember.
  242.      */
  243.     optind = 1;
  244.     opterr = 0;
  245.     while ((c = Sys::getopt(argc, argv, opts)) != -1)
  246. switch (c) {
  247. case 'o': case 'O':
  248.     fatal("No support for old protocol");
  249.     /*NOTREACHED*/
  250. #ifdef HTTP_SUPPORT
  251. case 'h': handlers.append(new HTTPSuperServer(optarg)); break;
  252. case 'H':
  253.     { HTTPFaxServer* server = new HTTPFaxServer;
  254.       server->open();
  255.       handlers.append(server);
  256.     }
  257.     break;
  258. #else
  259. case 'h': case 'H':
  260.     fatal("No HTTP suport");
  261.     /*NOTREACHED*/
  262. #endif
  263. case 'f':
  264.     addressfamily = strdup(optarg); break;
  265. case 'l':
  266.     bindaddress = strdup(optarg); break;
  267. case 'i': {
  268. InetSuperServer* iss;
  269. iss = new InetSuperServer(optarg);
  270. handlers.append(iss);
  271. if ((iss!=NULL) && (bindaddress!=NULL))
  272.     iss->setBindAddress(bindaddress);
  273.     iss->setAddressFamily(addressfamily);
  274. }
  275. break;
  276. case 'I': newInetServer(); break;
  277. #ifdef SNPP_SUPPORT
  278. case 's': handlers.append(new SNPPSuperServer(optarg)); break;
  279. case 'S':
  280.     { SNPPServer* server = new SNPPServer;
  281.       server->open();
  282.       handlers.append(server);
  283.     }
  284.     break;
  285. #else
  286. case 's': case 'S':
  287.     fatal("No SNPP support");
  288.     /*NOTREACHED*/
  289. #endif
  290. #if CONFIG_UNIXTRANSPORT
  291. case 'u': handlers.append(new UnixSuperServer(optarg)); break;
  292. #else
  293. case 'u':
  294.     fatal("No support for Unix domain sockets");
  295.     /*NOTREACHED*/
  296. #endif
  297. }
  298.     if (handlers.length() == 0)
  299. newInetServer();
  300.     /*
  301.      * Startup protocol processing.
  302.      */
  303.     if (setjmp(problem) == 0) {
  304. signal(SIGHUP, fxSIGHANDLER(sigCleanup));
  305. signal(SIGINT, fxSIGHANDLER(sigCleanup));
  306. signal(SIGQUIT, fxSIGHANDLER(sigCleanup));
  307. signal(SIGILL, fxSIGHANDLER(sigCleanup));
  308. signal(SIGKILL, fxSIGHANDLER(sigCleanup));
  309. signal(SIGBUS, fxSIGHANDLER(sigCleanup));
  310. signal(SIGSEGV, fxSIGHANDLER(sigCleanup));
  311. for (;;)
  312.     Dispatcher::instance().dispatch();
  313.     }
  314.     /*
  315.      * We explicitly destroy protocol threads so that any
  316.      * resources are reclaimed (e.g. Unix domain sockets).
  317.      */
  318.     for (u_int i = 0, n = handlers.length(); i < n; i++)
  319. delete handlers[i];
  320.     return 0;
  321. }