123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956 |
- /*
- * CDE - Common Desktop Environment
- *
- * Copyright (c) 1993-2012, The Open Group. All rights reserved.
- *
- * These libraries and programs are free software; you can
- * redistribute them and/or modify them under the terms of the GNU
- * Lesser General Public License as published by the Free Software
- * Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * These libraries and programs are distributed in the hope that
- * they will be useful, but WITHOUT ANY WARRANTY; without even the
- * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU Lesser General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with these libraries and programs; if not, write
- * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
- * Floor, Boston, MA 02110-1301 USA
- */
- //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
- //%% (c) Copyright 1993, 1994 International Business Machines Corp.
- //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
- //%% (c) Copyright 1993, 1994 Novell, Inc.
- //%% $TOG: mp_server.C /main/10 1999/10/14 18:38:32 mgreess $
- /*
- * @(#)mp_server.C 1.119 95/09/26
- *
- * Copyright (c) 1992 by Sun Microsystems, Inc.
- */
- #include "tt_options.h"
- #include "mp_s_global.h"
- #include "mp/mp_mp.h"
- #include "mp_s_mp.h"
- #include "mp_ptype.h"
- #include "mp_s_session.h"
- #include "mp_typedb.h"
- #include "util/copyright.h"
- #include "util/tt_enumname.h"
- #include "util/tt_global_env.h"
- #include "util/tt_port.h"
- #include "util/tt_gettext.h"
- #include "db/db_server.h"
- #include <locale.h>
- #include <sys/wait.h>
- #include <sys/stat.h>
- #include <errno.h>
- #define MAXARGS 256
- #define MAXPIDS 256
- #include <sys/resource.h>
- #include <unistd.h>
- #if defined(sgi) || defined(CSRG_BASED)
- #include <getopt.h>
- #endif
- TT_INSERT_COPYRIGHT
- #ifdef OPT_PATCH
- static char PatchID[] = "Patch Id: 100626_03.";
- static int Patch_ID100626_03;
- #endif
- // flag set by the signal handler function whenever we receive a
- // signal that the types database changed.
- int signal_types_changed = 0;
- int signal_toggle_trace = 0;
- // option_classing_engine determines whether we use the Classing Engine
- // to read the ptype/otype database. It's starting value determines the
- // default.
- int option_classing_engine = 0;
- // if equal to 1 then this option means that non process-tree
- // ttsessions will fork a child and exit when the child ttsession is
- // ready to service clients.
- int background_mode = 1;
- // this is a special case of a process-tree session that forks a child
- // ttsession (rather than forking a root process) and then prints out
- // the child ttsession session id when it is ready to service clients.
- int print_sessid = 0;
- // the level of authorization we are to use. one of: "unix", "none",
- // or "des". The default is "none".
- char *option_auth_level = (char *)0;
- // Whether to maximize the fd limit.
- int option_maximize_procids = 0;
- // the pid of the root process that gets forked in a process-tree
- // session, or of the child ttsession
- pid_t forked_pid = (pid_t)-1;
- void sig_handler(int sig);
- #ifdef OPT_XTHREADS
- static void init_self();
- #endif
- // buffer used to write out the session id of a child ttsession when the
- // special print_sessid option is turned on.
- char session_buf[255];
- // pipe used by print_sessid to communicate the session id from
- // the child ttsession to the parent ttsession.
- int ds_fds[2];
- // Sink for ttsession error output. If 0, output goes to syslog.
- FILE *errstr = stderr;
- pid_t child_waited_for;
- //
- // failed_procs is used to record any forked processes that have
- // exited. Essentially it is a circular list of pids. Because it is
- // typically updated inside a signal handler, it cannot use
- // dynamically allocated memory so it is implemented as a fixed-size
- // array of pids with two pointers into the array: _tt_s_mp->fin is an
- // index into the first unset slot in the array. When a child process
- // exits it's pid is recorded in this slot and the _tt_s_mp->fin index
- // is incremented. The other index records the last "processed" slot.
- // It is the last slot that was processed by the notify_start_failure
- // routine that processes this list of pids. Whenever _tt_s_mp->fin is
- // not equal to _tt_s_mp->fout then new pids were added to the list
- // and need to be processed by notify_start_failure. Note that the
- // indexes wrap around to 0 when they reach MAXPIDS. This means that
- // if more than MAXPIDS processes are entered into failed_procs before
- // they are consumed by notify_start_failure then some of the failed
- // processes won't get handled properly. This event was considered
- // unlikely but if it starts to happen then a larger value of MAXPIDS
- // should be chosen.
- //
- // (see notify_start_failure, sig_handler, _Tt_s_mp::main_loop, and
- // _Tt_s_mp::_Tt_s_mp)
- pid_t failed_procs[MAXPIDS];
- // Forward declarations
- void install_signal_handler();
- void notify_start_failure();
- int init_types();
- void print_usage_and_exit();
- //
- // Returns diagnosed child exit status, or -1 if we are not convinced
- // the child exited.
- //
- int
- child_exit_status(pid_t child, _Tt_wait_status status)
- {
- if (WIFEXITED(status)) {
- return WEXITSTATUS(status);
- } else if (WIFSIGNALED(status)) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 2,
- "child (%d) exited due to signal %d%s" ),
- child, WTERMSIG(status),
- WCOREDUMP(status) ?
- catgets( _ttcatd, 3, 3,
- " (core dumped)" )
- : "" );
- return 1;
- } else {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 4,
- "child (%d) neither exited nor "
- "was signaled!" ),
- child );
- return -1;
- }
- }
- int main(int argc, char **argv)
- {
- char *cmd = (char *)0;
- char *cargv[MAXARGS];
- int c;
- extern char *optarg;
- extern int optind;
- extern int opterr;
- int maxfds;
- Tt_status status;
- _Tt_wait_status ch_status;
- int i;
- //
- // Initialize all the global objects needed.
- //
- _tt_global = new _Tt_global();
- _tt_s_mp = new _Tt_s_mp;
- _tt_mp = (_Tt_mp *)_tt_s_mp;
- _tt_s_mp->exit_main_loop = 1;
- //
- // parse command-line options
- //
- // used by other objects when they need to print out error
- // messages to the user.
- _tt_global->progname = argv[0];
- setlocale( LC_ALL, "" );
- _tt_openlog( _tt_global->progname, LOG_PID | LOG_CONS | LOG_NOWAIT,
- LOG_DAEMON );
- // needed by the getopt call
- opterr = 0;
- while ((c = getopt(argc, argv, "A:pa:htvcd:sSXEN")) != -1) {
- switch (c) {
- case 'A':
- // set maximum number of undelivered messages
- // in ttsession.
- _tt_s_mp->max_active_messages = atoi(optarg);
- break;
- case 'a':
- // set authorization level
- option_auth_level = optarg;
- break;
- case 'S':
- // don't fork and exit (which is the default).
- background_mode = 0;
- break;
- case 's':
- // don't print out any status messages
- _tt_global->silent = 1;
- break;
- case 'v':
- // print versions and exit
- _TT_PRINT_VERSIONS((char *)_tt_global->progname)
- exit(0);
- case 'c':
- // process-tree session. Parse the rest of the
- // command-line arguments as arguments to the
- // process-tree program. This means that -c
- // should always be the last ttsession option
- // used.
-
- // set up the server session to be a
- // process-tree session.
- _tt_mp->initial_session->set_env(_TT_ENV_PROCESS_TREE,
- (char *)0);
- // set up buffer of arguments to pass to the
- // program we're going to fork as the root of
- // the process-tree
- for (i=0;argv[optind] && i < MAXARGS; i++, optind++) {
- cargv[i] = argv[optind];
- }
- if (i==MAXARGS) {
- errno = E2BIG;
- _tt_syslog( errstr, LOG_ERR, "%m" );
- exit(1);
- }
- cargv[i] = NULL;
- // if no program given then use $SHELL
- if (! cargv[0]) {
- cargv[0] = getenv("SHELL");
- cargv[1] = NULL;
- }
- cmd = cargv[0];
- background_mode = 0;
- // exit out of command-processing here
- // (otherwise, getopt will want to reparse the
- // arguments!)
- goto endopt;
- case 'd':
- // set up an X tooltalk session to the given X
- // display.
- if (getenv("DISPLAY") == 0) {
- _tt_putenv( "DISPLAY", optarg );
- }
- _tt_mp->initial_session->set_env(_TT_ENV_X11, optarg);
- break;
- case 't':
- // turn message tracing on.
- tt_trace_control( 1 );
- break;
- case 'p':
- // set up a process-tree session but rather
- // than fork a program as the root of the
- // process-tree, just set up the tooltalk
- // session and then print out the session id
- // to stdout. Programs can then manually set
- // the _TT_SESSION or _SUN_TT_SESSION environment variable to
- // this value to communicate.
- _tt_mp->initial_session->set_env(_TT_ENV_PROCESS_TREE,
- (char *)0);
- cmd = (char *)0;
- print_sessid = 1;
- break;
- #ifdef OPT_CLASSING_ENGINE
- case 'E':
- // turn on use of Classing Engine
- option_classing_engine = 1;
- break;
- #endif
- case 'X':
- option_classing_engine = 0;
- break;
- case 'N':
- option_maximize_procids = 1;
- break;
- case 'h':
- case '?':
- default:
- // error or help request.
- print_usage_and_exit();
- break;
- }
- }
- endopt:
- if (option_maximize_procids && (_tt_zoomdtablesize() != 0)) {
- _tt_syslog( errstr, LOG_WARNING,
- catgets( _ttcatd, 3, 5,
- "cannot maximize clients because %m"));
- }
- // sanity check
- if (_tt_mp->initial_session->env() == _TT_ENV_LAST) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 6,
- "No scope to manage. Use -c, -p, "
- "-d, or set $DISPLAY." ));
- exit(1);
- }
- //
- // set authorization level to either the command-line option,
- // the value of $TOOLTALK_AUTH_LEVEL or the default.
- //
- if (option_auth_level == (char *)0) {
- option_auth_level = getenv("TOOLTALK_AUTH_LEVEL");
- }
- if (option_auth_level == (char *)0) {
- _tt_mp->initial_session->set_auth_level(_TT_AUTH_ICEAUTH);
- } else if (!strcmp(option_auth_level, "unix")) {
- _tt_mp->initial_session->set_auth_level(_TT_AUTH_UNIX);
- _tt_s_mp->unix_cred_chk_flag = 1;
- } else if (!strcmp(option_auth_level, "cookie")) {
- _tt_mp->initial_session->set_auth_level(_TT_AUTH_ICEAUTH);
- } else if (!strcmp(option_auth_level,"des")) {
- _tt_mp->initial_session->set_auth_level(_TT_AUTH_DES);
- } else if (!strcmp(option_auth_level,"none")) {
- _tt_mp->initial_session->set_auth_level(_TT_AUTH_NONE);
- } else {
- print_usage_and_exit();
- }
- // check for conflicting options being set.
- if (background_mode && ! print_sessid &&
- _tt_mp->initial_session->env() == _TT_ENV_PROCESS_TREE) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 7,
- "Cannot use -S option with -c" ));
- exit(1);
- }
- install_signal_handler();
- signal(SIGCHLD, SIG_DFL);
- // set up a pipe which will be used by the child ttsession to
- // communicate it's session id to the parent ttsession which
- // will then print that out and then exit. (see SIGTERM case
- // in sig_handler below).
- if (print_sessid) {
- pipe(ds_fds);
- }
- if (!background_mode || (forked_pid=fork())==0) {
- // We are here if and only if we are a ttsession process
- // that will manage a session.
- // set ourselves to be the process group leader
- // so that our parent's signals won't propagate
- // down to us.
- if (!background_mode) {
- setpgid(0,0);
- }
- // re-install signal handler
- install_signal_handler();
- // Call the s_init method for _tt_mp. This will
- // cause the initial server session to be initiated
- // (ie. setup for rpc servicing and advertising our
- // address to tooltalk clients).
- status = _tt_s_mp->s_init();
- // now we check startup status, if we found another
- // session running then we return status=2. For other
- // errors we return status=1. (See auto-start code in
- // mp_session.cc in _Tt_session::init)
- switch (status) {
- case TT_OK:
- // rpc servicing has been initiated. Now we
- // can continue the initialization process.
- // This process is done this way because we
- // want to set up rpc servicing as soon as
- // possible so that clients can begin
- // contacting ttsession (they won't get
- // replies back until we're done with
- // initialization but that's ok).
- if (print_sessid) {
- // write our session id to a pipe that
- // was set up by our parent.
- sprintf(session_buf,"%s\n",
- (char *)(_tt_mp->initial_session->address_string()));
- write(ds_fds[1], session_buf, 255);
- }
- // initialize ptypes/otypes
- if (! init_types()) {
- // init_types() has emitted diagnostic
- exit(1);
- }
- // if we are running as a child ttsession then
- // we're now at a point where we're ready to
- // start servicing clients so kill off our
- // parent.
- if (background_mode) {
- // now were ready to accept requests so
- // kill the parent app.
- kill(getppid(), SIGTERM);
- }
- break;
- case TT_ERR_SESSION:
- // couldn't initialize because there's already
- // a ttsession running in our session scope.
- exit(2);
- case TT_ERR_NOMP:
- exit(1);
- break;
- default:
- _tt_syslog( errstr, LOG_ERR,
- "_Tt_s_session::s_init(): %d (%s)!",
- status, _tt_enumname(status));
- exit(1);
- }
- } else {
- // We're running as a parent ttsession, and we will
- // not be managing a ToolTalk session. Wait for our
- // child ttsession to either exit or kill us off with
- // a SIGTERM indicating it's ready.
- if (waitpid(forked_pid, &ch_status, 0) < 0) {
- //
- // Our signal handler should have called exit()!
- //
- _tt_syslog( errstr, LOG_ERR, "wait(): %m" );
- exit(1);
- }
- // if the wait returns then child ttsession must have
- // died abnormally. Return the status returned by the
- // child process.
- if (WIFEXITED(ch_status)) {
- // An exit status==2 is returned if the child
- // ttsession already found a session that is
- // active so we avoid printing out an error
- // message in this case.
- int exitStatus = WEXITSTATUS(ch_status);
- if (exitStatus != 2) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 8,
- "child ttsession exited"
- " with status %d" ),
- exitStatus );
- }
- exit(exitStatus);
- } else if (WIFSIGNALED(ch_status)) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 9,
- "child ttsession exited due "
- "to signal %d%s" ),
- WTERMSIG(ch_status),
- WCOREDUMP(ch_status) ?
- catgets( _ttcatd, 3, 10,
- " (core dumped)" )
- : "" );
- exit(1);
- } else {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 11,
- "child ttsession neither "
- "exited nor was signaled!" ));
- exit(1);
- }
- }
- //
- // if we're in a process-tree session then fork the requested
- // root process (contained in "cmd"). This process will then
- // be monitored by the signal handler such that if it exits
- // then the signal handler will also abort the tooltalk
- // session.
- //
- if (cmd != (char *)0 &&
- _tt_mp->initial_session->env() == _TT_ENV_PROCESS_TREE) {
- int i;
- switch(forked_pid = fork()) {
- case -1:
- _tt_syslog( errstr, LOG_ERR, "fork(): %m" );
- exit(1);
- case 0:
- maxfds = _tt_getdtablesize();
- for (i = 3; i < maxfds; i++) {
- close(i);
- }
- _tt_restoredtablesize();
- signal(SIGHUP, SIG_IGN);
- execvp(cmd,
- cargv);
- _tt_syslog( errstr, LOG_ERR, "execvp(): %m" );
- exit(1);
- break;
- default:
- #if !defined(OPT_BSD_WAIT)
- child_waited_for = waitpid(-1, 0, WNOHANG);
- #else
- child_waited_for = wait3(&ch_status, WNOHANG, 0);
- #endif
- if (child_waited_for < 0) {
- _tt_syslog( errstr, LOG_ERR, "waitpid(): %m" );
- if (errno == ECHILD) {
- exit(1);
- }
- } else if (child_waited_for == forked_pid) {
- //
- // XXX This really cannot happen here,
- // because we handle SIGCHLD, so this
- // all happens in sig_handler()
- //
- int xstat = child_exit_status(
- child_waited_for, ch_status );
- if (xstat >= 0) {
- exit( xstat );
- }
- }
- break;
- }
- }
- if ((! background_mode) && (print_sessid)) {
- printf("%s\n",
- (char *)_tt_mp->initial_session->address_string());
- fflush(stdout);
- }
- #ifdef OPT_XTHREADS
- // Set the global lock. This basically locks out the init_self
- // thread until it is given permission to proceed. Locks are
- // given up just before RPC calls and upon thread exits.
- // Only this initial call should use mutex_lock as opposed
- // to _tt_global->grab_mutex, because here we do not want
- // to wait on the condition variable here.
- _tt_global->grab_mutex();
-
- // Initialize as a client of ourself. Ignore failure.
- xthread_fork((void *(*)(void *)) init_self, NULL);
- #else
- _tt_s_mp->init_self();
- #endif
- //
- // main service loop. We basically check for any programs we
- // forked exiting, check for flags set by the signal handler
- // (_tt_s_mp->exit_main_loop means exit out of rpc servicing,
- // signal_types_changed means we got a signal to re-read the
- // types database). If no signal flags were set or programs
- // exited, then we just invoke the _Tt_s_mp::main_loop method
- // to service rpc requests.
- //
- if (background_mode) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 12, "starting" ));
- // We are in daemon mode, so error output goes to syslog.
- errstr = 0;
- }
- while (1) {
- _tt_s_mp->exit_main_loop = 0;
- if (_tt_s_mp->fout != _tt_s_mp->fin) {
- notify_start_failure();
- }
- _tt_s_mp->main_loop();
- if (_tt_s_mp->xfd == -2) {
- // X server exited
- break;
- }
- //
- // exit from main_loop method is the result of
- // a signal (see sig_handler below)
- //
- if (signal_types_changed) {
- if (init_types()) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 13,
- "have re-read types"));
- } else {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 14,
- "error in types; "
- "keeping old types" ));
- }
- signal_types_changed = 0;
- }
- if (signal_toggle_trace) {
- int was_on = tt_trace_control( -1 );
- _tt_syslog( errstr, LOG_ERR,
- "tt_trace_control( %d )", !was_on );
- signal_toggle_trace = 0;
- }
- if (_tt_s_mp->fout != _tt_s_mp->fin) {
- notify_start_failure();
- }
- }
- delete _tt_mp;
- exit(0);
- }
- #ifdef OPT_XTHREADS
- static void init_self()
- {
- _tt_s_mp->init_self();
- xthread_exit(0);
- }
- #endif
- //
- // This routine is called whenever _tt_s_mp->fin is not equal to
- // _tt_s_mp->fout (see comment for failed_procs above). This condition
- // signals that an asynchronous signal from the system came in telling us
- // that a child process exited. What we need to do is search the list of
- // ptypes for ptypes that are in the process of launching (see
- // _Tt_ptype::launch). If we find one whose start pid matches one of the
- // pids in the failed_procs array then we invoke the
- // _Tt_ptype::launch_failed method to arrange for the _Tt_ptype object to
- // handle this condition. The reason that this launch failure is special
- // is that a ptype that is in the process of being launched may not have
- // gotten far enough to launch a process that connects with ttsession so
- // the only mechanism we have to detect the failure is that the process
- // exited. What this means is that a process in a ptype's start string
- // cannot exit until it either connects with ttsession and replies to its
- // start message or until a process it launches does so.
- //
- void notify_start_failure()
- {
- // one of the starting ptypes failed to start.
- // Find which one it was and fail all the
- // messages waiting for it.
- // XXX: there should be better data-structure
- // support so we wouldn't have to iterate
- // through all the ptypes.
- _Tt_ptype_table_cursor ptypes;
- int ptype_found;
- while (_tt_s_mp->fout != _tt_s_mp->fin) {
- ptypes.reset(_tt_s_mp->ptable);
- ptype_found = 0;
- while (!ptype_found && ptypes.next()) {
- if (failed_procs[_tt_s_mp->fout]==ptypes->start_pid()) {
- if (ptypes->launching()) {
- ptypes->launch_failed();
- ptype_found = 1;
- }
- }
- }
- _tt_s_mp->fout++;
- if (_tt_s_mp->fout == MAXPIDS) {
- _tt_s_mp->fout = 0;
- }
- }
- }
- //
- // Install sig_handler as the handler for all the signals it handles.
- //
- void
- install_signal_handler()
- {
- _Tt_string err = "_tt_sigset(SIG";
- if (_tt_sigset(SIGHUP, &sig_handler) == 0) {
- _tt_syslog( errstr, LOG_WARNING, err.cat("HUP)"));
- }
- if (_tt_sigset(SIGTERM, &sig_handler) == 0) {
- _tt_syslog( errstr, LOG_WARNING, err.cat("TERM)") );
- }
- if (_tt_sigset(SIGINT, &sig_handler) == 0) {
- _tt_syslog( errstr, LOG_WARNING, err.cat("INT)") );
- }
- if (_tt_sigset(SIGUSR1, &sig_handler) == 0) {
- _tt_syslog( errstr, LOG_WARNING, err.cat("USR1)") );
- }
- if (_tt_sigset(SIGUSR2, &sig_handler) == 0) {
- _tt_syslog( errstr, LOG_WARNING, err.cat("USR2)") );
- }
- if (_tt_sigset(SIGCHLD, &sig_handler) == 0) {
- _tt_syslog( errstr, LOG_WARNING, err.cat("CHLD)") );
- }
- if (_tt_sigset(SIGPIPE, &sig_handler) == 0) {
- _tt_syslog( errstr, LOG_WARNING, err.cat("PIPE)") );
- }
- }
- //
- // Reads in the ptype/otype database from the XDR (or CE) database.
- // Once the types are read in from the database the types are installed
- // via the appropiate _Tt_s_mp methods install_ptable and install_otable.
- // Keep a pointer to the _Tt_typedb structure so we can merge in
- // more types later on via tt_session_types_load.
- //
- int
- init_types()
- {
- Tt_status err;
- #ifdef OPT_CLASSING_ENGINE
- _Tt_typedb::ce2xdr();
- #endif
- _tt_s_mp->tdb = new _Tt_typedb();
- if (option_classing_engine) {
- err = _tt_s_mp->tdb->init_ce();
- if (err != TT_OK) {
- if (0==getenv("OPENWINHOME")) {
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 15,
- "$OPENWINHOME not set"));
- }
- return(0);
- }
- } else {
- err = _tt_s_mp->tdb->init_xdr();
- switch (err) {
- case TT_OK:
- case TT_ERR_NO_MATCH:
- case TT_ERR_DBCONSIST:
- case TT_ERR_PATH:
- break;
- default:
- _tt_syslog( errstr, LOG_ERR,
- "_Tt_typedb::init_xdr(): %s",
- _tt_enumname(err));
- }
- if (err != TT_OK) {
- return(0);
- }
- }
- _tt_s_mp->install_ptable(_tt_s_mp->tdb->ptable);
- _tt_s_mp->install_otable(_tt_s_mp->tdb->otable);
- return(1);
- }
- //
- // Prints out a usage string and exits.
- //
- void
- print_usage_and_exit()
- {
- _tt_syslog( errstr, LOG_ERR, "%s%s%s%s%s",
- catgets( _ttcatd, 3, 16,
- "\nUsage: ttsession [-a cookie|unix|des][-d display][-spStvhNX" ),
- #if defined(OPT_CLASSING_ENGINE)
- "E",
- #else
- "",
- #endif
- catgets( _ttcatd, 3, 17,
- "][-c command]\n"
- " -c [command] start a process tree session, and run command in it.\n"
- " Subsequent options are passed to command. Default: $SHELL\n"
- " -p start a process tree session, and print its id\n"
- " -d display start an X session on display\n"
- "\n"
- " -a cookie|unix|des set server authentication level\n"
- " -s silent. Don't print out any warnings\n"
- " -S don't fork into the background\n"
- " -N maximize the number of clients allowed\n"
- " -t turn on message tracing\n"
- " -X use XDR databases for static types (default)\n" ),
- #if defined(OPT_CLASSING_ENGINE)
- catgets( _ttcatd, 3, 18,
- " -E use Classing Engine for static types\n" ),
- #else
- "",
- #endif
- catgets( _ttcatd, 3, 19,
- "\n"
- " -v print out version number\n"
- " -h print out this message\n"
- "\n"
- "Signal interface:\n"
- " kill -USR1 ttsession_pid toggle message tracing\n"
- " kill -USR2 ttsession_pid re-read static types" ) );
- exit(1);
- }
- //
- // Global signal handler for ttsession. All signals are handled by this
- // function (ie. no signal handlers should be defined in any other files)
- //
- void
- sig_handler(int sig)
- {
- int intrs = 100;
- pid_t child_pid;
- _Tt_wait_status status;
- switch (sig) {
- case SIGPIPE:
- // usually the result of a write on a broken tcp
- // socket. Default action is to ignore it.
- break;
- case SIGHUP:
- break;
- case SIGCHLD:
- // a child process has exited. If the process that
- // exited is the root process of a process-tree
- // session then we exit. Otherwise, it is possibly a
- // ptype that we launched so we record its pid in the
- // failed_procs list (see comment above for
- // failed_procs).
- #if !defined(OPT_BSD_WAIT)
- // XXX: the sysv code should do the same loop as
- // below.
- child_pid = waitpid(-1, &status, WNOHANG);
- #else
- // we do an asynchronous wait on the child to get its
- // pid. However the wait3 call can be interrupted and
- // return an EINTR so we keep trying for a bounded
- // amount of time.
- while (((child_pid = wait3(&status, WNOHANG, 0)) == -1)
- && errno == EINTR) {
- if (! intrs--) {
- _tt_syslog( errstr, LOG_ERR, "wait3(): %m" );
- break;
- }
- }
- #endif // OPT_BSD_WAIT
- // check for the child pid being the root process of a
- // process-tree id and exit if it is. Otherwise record
- // the pid in the failed_procs list and set
- // _tt_s_mp->exit_main_loop to 1 to signal the main
- // event loop to break out of rpc servicing to handle
- // this condition.
- if (child_pid > 0) {
- int status2exit = child_exit_status(child_pid, status);
- int isdead = status2exit >= 0;
- if (isdead) {
- if (child_pid == forked_pid) {
- // calling free in a sig handler is a no-no
- // delete _tt_mp;
- exit(status2exit);
- }
- else
- #ifdef OPT_XTHREADS
- if(child_pid !=
- _tt_s_mp->garbage_collector_pid)
- #endif
- {
- failed_procs[_tt_s_mp->fin] = child_pid;
- _tt_s_mp->fin++;
- if (_tt_s_mp->fin == MAXPIDS) {
- _tt_s_mp->fin = 0;
- }
- }
-
- }
- _tt_s_mp->exit_main_loop = 1;
- return;
- }
- _tt_syslog( errstr, LOG_WARNING, "waitpid(): %m");
- break;
- case SIGTERM:
- // this signal is sent by a forked ttsession when it
- // is ready to start servicing clients. It is our
- // signal to exit. For the special case of a "dialin"
- // session we print out the child session's id.
- if ((background_mode) && (forked_pid > 0)) {
- if (print_sessid) {
- memset(session_buf, 0, 255);
- read(ds_fds[0], session_buf, 255 - 1);
- printf("%s", session_buf);
- }
- // this is the signal from the forked
- // ttsession that we should exit.
- exit(0);
- }
- // The child ttsession falls through to clean itself up
- case SIGINT:
- _tt_syslog( errstr, LOG_ERR,
- catgets( _ttcatd, 3, 20, "exiting" ));
- // if this is a process tree system, let our kid know
- // it's time to depart. It's important to allow the
- // process tree root process to exit beforehand so
- // that the controlling terminal will get properly
- // reassigned. Otherwise, the SIGINT will cause the
- // entire process hierarchy that has the same
- // controlling terminal to exit (so for example your
- // shelltool window would die because ttsession was
- // killed in process-tree mode).
-
- if (forked_pid > 0
- && 0 == kill(forked_pid, SIGINT)) {
- // Wait for a decent interval to give him a chance
- // to clean up
- int i;
- for (i=0; i<10; i++) {
- sleep(1);
- if (forked_pid ==
- waitpid(forked_pid, 0, WNOHANG)) {
- break;
- }
- }
- if (i==10) {
- // Won't go away, eh? Time to get tough.
- if (0 == kill(forked_pid, SIGKILL)) {
- waitpid(forked_pid, 0, 0);
- }
- }
- }
- // calling free in a sig handler is a no-no
- // delete _tt_mp;
- exit(1);
- break;
- case SIGUSR1:
- // signal to toggle message tracing
- signal_toggle_trace = 1;
- break;
- case SIGTYPES:
- // signal to reread types database
- _tt_s_mp->exit_main_loop = 1;
- signal_types_changed = 1;
- break;
- default:
- break;
- }
- }
|