File: main.c%2B%2B

package info (click to toggle)
hylafax 1%3A4.1.1-3.1
  • links: PTS
  • area: main
  • in suites: woody
  • size: 6,400 kB
  • ctags: 7,270
  • sloc: sh: 15,895; ansic: 12,661; makefile: 1,439; cpp: 850
file content (328 lines) | stat: -rw-r--r-- 10,150 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/*	$Id: main.c++,v 1.3 2001/04/13 00:07:21 robert Exp $ */
/*
 * Copyright (c) 1995-1996 Sam Leffler
 * Copyright (c) 1995-1996 Silicon Graphics, Inc.
 * HylaFAX is a trademark of Silicon Graphics
 *
 * Permission to use, copy, modify, distribute, and sell this software and 
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names of
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Sam Leffler and Silicon Graphics.
 * 
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
 * 
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
 * OF THIS SOFTWARE.
 */
#include "port.h"
#include "InetFaxServer.h"
#if CONFIG_UNIXTRANSPORT
#include "UnixFaxServer.h"
#endif
#ifdef OLDPROTO_SUPPORT
#include "OldProtocol.h"
#endif
#ifdef SNPP_SUPPORT
#include "SNPPServer.h"
#endif
#ifdef HTTP_SUPPORT
#include "HTTPServer.h"
#endif
#include "Dispatcher.h"
#include "Array.h"
#include "Sys.h"
#include "Socket.h"
#include "config.h"

static	jmp_buf problem;

static void
sigCleanup(int sig)
{
    logError("CAUGHT SIGNAL %d", sig);
    longjmp(problem, 1);
}

static void
fatal(const char* fmt ...)
{
    va_list ap;
    va_start(ap, fmt);
    vlogError(fmt, ap);
    va_end(ap);
    exit(-1);
}

#define	PATH_DEVNULL	"dev/null"
#define	PATH_DEVTCP	"dev/tcp"
#define	PATH_NETCONFIG	"etc/netconfig"
#define	PATH_DEVSOCKSYS	"dev/socksys"

/*
 * Verify and possibly setup the chroot'd filesystem as
 * required by the system.  Specifically, create a private
 * copy of /dev/null and any networking-related files
 * required by SVR4-based TCP/IP support.  We do this work
 * because the process runs chroot'd to the top of the
 * spooling area so normal files in the root filesystem
 * are inaccessible.
 *
 * NB: This work could be done once in a setup script but
 *     creating duplicates of character special device files
 *     is not simple from the shell.
 */
static void
CheckSpoolingSetup(void)
{
    struct stat sb;
    uid_t ouid = geteuid();
    (void) seteuid(0);
    mode_t omask = umask(0);
    /*
     * Craft a private /dev/null in the chroot'd filesystem
     * for use by syslog because some syslogs require this
     * to function correctly.
     */
    if (!Sys::isCharSpecialFile(PATH_DEVNULL)) {
	if (!Sys::isCharSpecialFile("/" PATH_DEVNULL, sb))
	    fatal("stat(%s): %s", "/" PATH_DEVNULL, strerror(errno));
	if (mknod(PATH_DEVNULL, sb.st_mode, sb.st_rdev) < 0)
	    fatal("Could not create %s: %s", PATH_DEVNULL, strerror(errno));
    }
    /*
     * If the system appears to support SVR4-style TCP/IP
     * support then craft a private copy of the necessary
     * files so that socket-related calls can be made after
     * chroot'ing to the top of the spooling area.
     *
     * NB: It is assumed that the dev subdirectory is already
     *     present (make install or similar should create it).
     */
    if (Sys::isCharSpecialFile("/" PATH_DEVTCP, sb) &&
      !Sys::isCharSpecialFile(PATH_DEVTCP)) {
	if (mknod(PATH_DEVTCP, sb.st_mode, sb.st_rdev) < 0)
	    fatal("Could not create %s: %s", PATH_DEVTCP, strerror(errno));
	/*
	 * Copy /etc/netconfig if not already present.
	 */
	if (Sys::stat(PATH_NETCONFIG, sb) < 0) {
	    int src = Sys::open("/" PATH_NETCONFIG, O_RDONLY);
	    if (src >= 0) {
		int dst = Sys::open(PATH_NETCONFIG, O_WRONLY|O_CREAT, 0444);
		if (dst < 0)
		    fatal("creat(%s): %s", PATH_NETCONFIG, strerror(errno));
		char buf[4096];
		int cc;
		while ((cc = read(src, buf, sizeof (buf))) > 0)
		    if (write(dst, buf, cc) < 0)
			fatal("write(%s): %s", PATH_NETCONFIG, strerror(errno));
		close(dst);
		close(src);
	    } else
		logWarning("%s: Cannot open: %s",
		    "/" PATH_NETCONFIG, strerror(errno));
	}
    }
    /*
     * SCO OS 5 apparently needs a /dev/socksys to implement
     * setsockopt calls (sigh); create one in the chroot'd
     * area if one exists in the root filesystem.
     */
    if (Sys::isCharSpecialFile("/" PATH_DEVSOCKSYS, sb) &&
      !Sys::isCharSpecialFile(PATH_DEVSOCKSYS))
	if (mknod(PATH_DEVSOCKSYS, sb.st_mode, sb.st_rdev) < 0)
	    fatal("Could not create %s: %s", PATH_DEVSOCKSYS, strerror(errno));
    (void) umask(omask);
    seteuid(ouid);
}

/*
 * Break the association with the controlling tty.
 * Note that we do not close all the open file descriptors
 * because many systems cache open descriptors within libraries
 * for performance reasons and do not react well when you close
 * them w/o telling them about it (and some don't react well
 * even when you *DO* tell them).  Since we know we're called
 * very early on from main in all our apps we just assume that
 * we only need to remove the stdin+stdout+stderr before forking
 * and starting a new session.
 */
static void
detachFromTTY(void)
{
    int fd = Sys::open(_PATH_DEVNULL, O_RDWR);
    dup2(fd, STDIN_FILENO);
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    switch (fork()) {
    case 0:	break;			// child, continue
    case -1:	_exit(1);		// error
    default:	_exit(0);		// parent, terminate
    }
    (void) setsid();
}

static void
usage(const char* appName)
{
    fatal("usage: %s [-o port] [-h port] [-i port] [-u socket] [-q queue-directory]",
	appName);
}

fxDECLARE_PtrArray(IOHandlerArray, IOHandler*)
fxIMPLEMENT_PtrArray(IOHandlerArray, IOHandler*)
static	IOHandlerArray handlers;

static void
newInetServer(void)
{
    InetFaxServer* server = new InetFaxServer;
    server->open();
    handlers.append(server);
}

int
main(int argc, char** argv, char** envp)
{
    HylaFAXServer::setLogFacility(LOG_FAX);
    HylaFAXServer::setupLogging("HylaFAX");
    HylaFAXServer::setupPermissions();

    fxStr appName = argv[0];
    u_int l = appName.length();
    appName = appName.tokenR(l, '/');

    optind = 1;
    opterr = 0;
    int c;
    const char* opts = "dHh:Ii:Oo:q:Ss:u:";
    /*
     * Deduce the spooling directory and whether or not to
     * detach the process from the controlling tty.  The
     * latter is complicated by the fact that we run both
     * as a master-server process and as a subprocess to
     * inetd.  If we are to act as a master-server then we
     * detach by default.  If we are invoked by inetd then
     * do not detach.  If no arguments are specified then
     * we imply a -I option (the new fax protocol) and do
     * not want to detach.  The logic is a touch convoluted
     * to do this correctly and is probably not worth the
     * effort (except to reduce configuration errors).
     */
    fxStr queueDir(FAX_SPOOLDIR);
    int detach = -1;			// unknown state
    while ((c = Sys::getopt(argc, argv, opts)) != -1)
	switch (c) {
	case 'h': case 'i': case 'o': case 's': case 'u':
	    if (detach == -1)		// detach unless explicitly specified
		detach = true;
	    break;
	case 'H': case 'I': case 'O': case 'S':
	    if (detach == -1)		// don't detach when invoked by inetd
		detach = false;
	    break;
	case 'd': detach = false; break;
	case 'q': queueDir = optarg; break;
	case '?': usage(appName);
	}
    if (detach == -1)			// no protocol options means -I
	detach = false;
    if (Sys::chdir(queueDir) < 0)
	fatal("Can not change directory to %s", (const char*)queueDir);
    CheckSpoolingSetup();
    if (detach)
	detachFromTTY();

    /*
     * Rescan the arguments and create the appropriate
     * protocol support threads.  We do this after the
     * above work for reasons I can no longer remember.
     */
    optind = 1;
    opterr = 0;
    while ((c = Sys::getopt(argc, argv, opts)) != -1)
	switch (c) {
#ifdef OLDPROTO_SUPPORT
	case 'o': handlers.append(new OldProtocolSuperServer(optarg)); break;
	case 'O':
	    { OldProtocolServer* server = new OldProtocolServer;
	      server->open();
	      handlers.append(server);
	    }
	    break;
#else
	case 'o': case 'O':
	    fatal("No support for old protocol");
	    /*NOTREACHED*/
#endif
#ifdef HTTP_SUPPORT
	case 'h': handlers.append(new HTTPSuperServer(optarg)); break;
	case 'H':
	    { HTTPFaxServer* server = new HTTPFaxServer;
	      server->open();
	      handlers.append(server);
	    }
	    break;
#else
	case 'h': case 'H':
	    fatal("No HTTP suport");
	    /*NOTREACHED*/
#endif
	case 'i': handlers.append(new InetSuperServer(optarg)); break;
	case 'I': newInetServer(); break;
#ifdef SNPP_SUPPORT
	case 's': handlers.append(new SNPPSuperServer(optarg)); break;
	case 'S':
	    { SNPPServer* server = new SNPPServer;
	      server->open();
	      handlers.append(server);
	    }
	    break;
#else
	case 's': case 'S':
	    fatal("No SNPP support");
	    /*NOTREACHED*/
#endif
#if CONFIG_UNIXTRANSPORT
	case 'u': handlers.append(new UnixSuperServer(optarg)); break;
#else
	case 'u':
	    fatal("No support for Unix domain sockets");
	    /*NOTREACHED*/
#endif
	}
    if (handlers.length() == 0)
	newInetServer();

    /*
     * Startup protocol processing.
     */
    if (setjmp(problem) == 0) {
	signal(SIGHUP, fxSIGHANDLER(sigCleanup));
	signal(SIGINT, fxSIGHANDLER(sigCleanup));
	signal(SIGQUIT, fxSIGHANDLER(sigCleanup));
	signal(SIGILL, fxSIGHANDLER(sigCleanup));
	signal(SIGKILL, fxSIGHANDLER(sigCleanup));
	signal(SIGBUS, fxSIGHANDLER(sigCleanup));
	signal(SIGSEGV, fxSIGHANDLER(sigCleanup));

	for (;;)
	    Dispatcher::instance().dispatch();
    }
    /*
     * We explicitly destroy protocol threads so that any
     * resources are reclaimed (e.g. Unix domain sockets).
     */
    for (u_int i = 0, n = handlers.length(); i < n; i++)
	delete handlers[i];
    return 0;
}