mp_server.C 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
  24. //%% (c) Copyright 1993, 1994 International Business Machines Corp.
  25. //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
  26. //%% (c) Copyright 1993, 1994 Novell, Inc.
  27. //%% $TOG: mp_server.C /main/10 1999/10/14 18:38:32 mgreess $
  28. /*
  29. * @(#)mp_server.C 1.119 95/09/26
  30. *
  31. * Copyright (c) 1992 by Sun Microsystems, Inc.
  32. */
  33. #include "tt_options.h"
  34. #include "mp_s_global.h"
  35. #include "mp/mp_mp.h"
  36. #include "mp_s_mp.h"
  37. #include "mp_ptype.h"
  38. #include "mp_s_session.h"
  39. #include "mp_typedb.h"
  40. #include "util/copyright.h"
  41. #include "util/tt_enumname.h"
  42. #include "util/tt_global_env.h"
  43. #include "util/tt_port.h"
  44. #include "util/tt_gettext.h"
  45. #include "db/db_server.h"
  46. #include <locale.h>
  47. #include <sys/wait.h>
  48. #include <sys/stat.h>
  49. #include <errno.h>
  50. #define MAXARGS 256
  51. #define MAXPIDS 256
  52. #include <sys/resource.h>
  53. #include <unistd.h>
  54. #if defined(sgi) || defined(CSRG_BASED)
  55. #include <getopt.h>
  56. #endif
  57. TT_INSERT_COPYRIGHT
  58. #ifdef OPT_PATCH
  59. static char PatchID[] = "Patch Id: 100626_03.";
  60. static int Patch_ID100626_03;
  61. #endif
  62. // flag set by the signal handler function whenever we receive a
  63. // signal that the types database changed.
  64. int signal_types_changed = 0;
  65. int signal_toggle_trace = 0;
  66. // option_classing_engine determines whether we use the Classing Engine
  67. // to read the ptype/otype database. It's starting value determines the
  68. // default.
  69. int option_classing_engine = 0;
  70. // if equal to 1 then this option means that non process-tree
  71. // ttsessions will fork a child and exit when the child ttsession is
  72. // ready to service clients.
  73. int background_mode = 1;
  74. // this is a special case of a process-tree session that forks a child
  75. // ttsession (rather than forking a root process) and then prints out
  76. // the child ttsession session id when it is ready to service clients.
  77. int print_sessid = 0;
  78. // the level of authorization we are to use. one of: "unix", "none",
  79. // or "des". The default is "none".
  80. char *option_auth_level = (char *)0;
  81. // Whether to maximize the fd limit.
  82. int option_maximize_procids = 0;
  83. // the pid of the root process that gets forked in a process-tree
  84. // session, or of the child ttsession
  85. pid_t forked_pid = (pid_t)-1;
  86. void sig_handler(int sig);
  87. #ifdef OPT_XTHREADS
  88. static void init_self();
  89. #endif
  90. // buffer used to write out the session id of a child ttsession when the
  91. // special print_sessid option is turned on.
  92. char session_buf[255];
  93. // pipe used by print_sessid to communicate the session id from
  94. // the child ttsession to the parent ttsession.
  95. int ds_fds[2];
  96. // Sink for ttsession error output. If 0, output goes to syslog.
  97. FILE *errstr = stderr;
  98. pid_t child_waited_for;
  99. //
  100. // failed_procs is used to record any forked processes that have
  101. // exited. Essentially it is a circular list of pids. Because it is
  102. // typically updated inside a signal handler, it cannot use
  103. // dynamically allocated memory so it is implemented as a fixed-size
  104. // array of pids with two pointers into the array: _tt_s_mp->fin is an
  105. // index into the first unset slot in the array. When a child process
  106. // exits it's pid is recorded in this slot and the _tt_s_mp->fin index
  107. // is incremented. The other index records the last "processed" slot.
  108. // It is the last slot that was processed by the notify_start_failure
  109. // routine that processes this list of pids. Whenever _tt_s_mp->fin is
  110. // not equal to _tt_s_mp->fout then new pids were added to the list
  111. // and need to be processed by notify_start_failure. Note that the
  112. // indexes wrap around to 0 when they reach MAXPIDS. This means that
  113. // if more than MAXPIDS processes are entered into failed_procs before
  114. // they are consumed by notify_start_failure then some of the failed
  115. // processes won't get handled properly. This event was considered
  116. // unlikely but if it starts to happen then a larger value of MAXPIDS
  117. // should be chosen.
  118. //
  119. // (see notify_start_failure, sig_handler, _Tt_s_mp::main_loop, and
  120. // _Tt_s_mp::_Tt_s_mp)
  121. pid_t failed_procs[MAXPIDS];
  122. // Forward declarations
  123. void install_signal_handler();
  124. void notify_start_failure();
  125. int init_types();
  126. void print_usage_and_exit();
  127. //
  128. // Returns diagnosed child exit status, or -1 if we are not convinced
  129. // the child exited.
  130. //
  131. int
  132. child_exit_status(pid_t child, _Tt_wait_status status)
  133. {
  134. if (WIFEXITED(status)) {
  135. return WEXITSTATUS(status);
  136. } else if (WIFSIGNALED(status)) {
  137. _tt_syslog( errstr, LOG_ERR,
  138. catgets( _ttcatd, 3, 2,
  139. "child (%d) exited due to signal %d%s" ),
  140. child, WTERMSIG(status),
  141. WCOREDUMP(status) ?
  142. catgets( _ttcatd, 3, 3,
  143. " (core dumped)" )
  144. : "" );
  145. return 1;
  146. } else {
  147. _tt_syslog( errstr, LOG_ERR,
  148. catgets( _ttcatd, 3, 4,
  149. "child (%d) neither exited nor "
  150. "was signaled!" ),
  151. child );
  152. return -1;
  153. }
  154. }
  155. int main(int argc, char **argv)
  156. {
  157. char *cmd = (char *)0;
  158. char *cargv[MAXARGS];
  159. int c;
  160. extern char *optarg;
  161. extern int optind;
  162. extern int opterr;
  163. int maxfds;
  164. Tt_status status;
  165. _Tt_wait_status ch_status;
  166. int i;
  167. //
  168. // Initialize all the global objects needed.
  169. //
  170. _tt_global = new _Tt_global();
  171. _tt_s_mp = new _Tt_s_mp;
  172. _tt_mp = (_Tt_mp *)_tt_s_mp;
  173. _tt_s_mp->exit_main_loop = 1;
  174. //
  175. // parse command-line options
  176. //
  177. // used by other objects when they need to print out error
  178. // messages to the user.
  179. _tt_global->progname = argv[0];
  180. setlocale( LC_ALL, "" );
  181. _tt_openlog( _tt_global->progname, LOG_PID | LOG_CONS | LOG_NOWAIT,
  182. LOG_DAEMON );
  183. // needed by the getopt call
  184. opterr = 0;
  185. while ((c = getopt(argc, argv, "A:pa:htvcd:sSXEN")) != -1) {
  186. switch (c) {
  187. case 'A':
  188. // set maximum number of undelivered messages
  189. // in ttsession.
  190. _tt_s_mp->max_active_messages = atoi(optarg);
  191. break;
  192. case 'a':
  193. // set authorization level
  194. option_auth_level = optarg;
  195. break;
  196. case 'S':
  197. // don't fork and exit (which is the default).
  198. background_mode = 0;
  199. break;
  200. case 's':
  201. // don't print out any status messages
  202. _tt_global->silent = 1;
  203. break;
  204. case 'v':
  205. // print versions and exit
  206. _TT_PRINT_VERSIONS((char *)_tt_global->progname)
  207. exit(0);
  208. case 'c':
  209. // process-tree session. Parse the rest of the
  210. // command-line arguments as arguments to the
  211. // process-tree program. This means that -c
  212. // should always be the last ttsession option
  213. // used.
  214. // set up the server session to be a
  215. // process-tree session.
  216. _tt_mp->initial_session->set_env(_TT_ENV_PROCESS_TREE,
  217. (char *)0);
  218. // set up buffer of arguments to pass to the
  219. // program we're going to fork as the root of
  220. // the process-tree
  221. for (i=0;argv[optind] && i < MAXARGS; i++, optind++) {
  222. cargv[i] = argv[optind];
  223. }
  224. if (i==MAXARGS) {
  225. errno = E2BIG;
  226. _tt_syslog( errstr, LOG_ERR, "%m" );
  227. exit(1);
  228. }
  229. cargv[i] = NULL;
  230. // if no program given then use $SHELL
  231. if (! cargv[0]) {
  232. cargv[0] = getenv("SHELL");
  233. cargv[1] = NULL;
  234. }
  235. cmd = cargv[0];
  236. background_mode = 0;
  237. // exit out of command-processing here
  238. // (otherwise, getopt will want to reparse the
  239. // arguments!)
  240. goto endopt;
  241. case 'd':
  242. // set up an X tooltalk session to the given X
  243. // display.
  244. if (getenv("DISPLAY") == 0) {
  245. _tt_putenv( "DISPLAY", optarg );
  246. }
  247. _tt_mp->initial_session->set_env(_TT_ENV_X11, optarg);
  248. break;
  249. case 't':
  250. // turn message tracing on.
  251. tt_trace_control( 1 );
  252. break;
  253. case 'p':
  254. // set up a process-tree session but rather
  255. // than fork a program as the root of the
  256. // process-tree, just set up the tooltalk
  257. // session and then print out the session id
  258. // to stdout. Programs can then manually set
  259. // the _TT_SESSION or _SUN_TT_SESSION environment variable to
  260. // this value to communicate.
  261. _tt_mp->initial_session->set_env(_TT_ENV_PROCESS_TREE,
  262. (char *)0);
  263. cmd = (char *)0;
  264. print_sessid = 1;
  265. break;
  266. #ifdef OPT_CLASSING_ENGINE
  267. case 'E':
  268. // turn on use of Classing Engine
  269. option_classing_engine = 1;
  270. break;
  271. #endif
  272. case 'X':
  273. option_classing_engine = 0;
  274. break;
  275. case 'N':
  276. option_maximize_procids = 1;
  277. break;
  278. case 'h':
  279. case '?':
  280. default:
  281. // error or help request.
  282. print_usage_and_exit();
  283. break;
  284. }
  285. }
  286. endopt:
  287. if (option_maximize_procids && (_tt_zoomdtablesize() != 0)) {
  288. _tt_syslog( errstr, LOG_WARNING,
  289. catgets( _ttcatd, 3, 5,
  290. "cannot maximize clients because %m"));
  291. }
  292. // sanity check
  293. if (_tt_mp->initial_session->env() == _TT_ENV_LAST) {
  294. _tt_syslog( errstr, LOG_ERR,
  295. catgets( _ttcatd, 3, 6,
  296. "No scope to manage. Use -c, -p, "
  297. "-d, or set $DISPLAY." ));
  298. exit(1);
  299. }
  300. //
  301. // set authorization level to either the command-line option,
  302. // the value of $TOOLTALK_AUTH_LEVEL or the default.
  303. //
  304. if (option_auth_level == (char *)0) {
  305. option_auth_level = getenv("TOOLTALK_AUTH_LEVEL");
  306. }
  307. if (option_auth_level == (char *)0) {
  308. _tt_mp->initial_session->set_auth_level(_TT_AUTH_ICEAUTH);
  309. } else if (!strcmp(option_auth_level, "unix")) {
  310. _tt_mp->initial_session->set_auth_level(_TT_AUTH_UNIX);
  311. _tt_s_mp->unix_cred_chk_flag = 1;
  312. } else if (!strcmp(option_auth_level, "cookie")) {
  313. _tt_mp->initial_session->set_auth_level(_TT_AUTH_ICEAUTH);
  314. } else if (!strcmp(option_auth_level,"des")) {
  315. _tt_mp->initial_session->set_auth_level(_TT_AUTH_DES);
  316. } else if (!strcmp(option_auth_level,"none")) {
  317. _tt_mp->initial_session->set_auth_level(_TT_AUTH_NONE);
  318. } else {
  319. print_usage_and_exit();
  320. }
  321. // check for conflicting options being set.
  322. if (background_mode && ! print_sessid &&
  323. _tt_mp->initial_session->env() == _TT_ENV_PROCESS_TREE) {
  324. _tt_syslog( errstr, LOG_ERR,
  325. catgets( _ttcatd, 3, 7,
  326. "Cannot use -S option with -c" ));
  327. exit(1);
  328. }
  329. install_signal_handler();
  330. signal(SIGCHLD, SIG_DFL);
  331. // set up a pipe which will be used by the child ttsession to
  332. // communicate it's session id to the parent ttsession which
  333. // will then print that out and then exit. (see SIGTERM case
  334. // in sig_handler below).
  335. if (print_sessid) {
  336. pipe(ds_fds);
  337. }
  338. if (!background_mode || (forked_pid=fork())==0) {
  339. // We are here if and only if we are a ttsession process
  340. // that will manage a session.
  341. // set ourselves to be the process group leader
  342. // so that our parent's signals won't propagate
  343. // down to us.
  344. if (!background_mode) {
  345. setpgid(0,0);
  346. }
  347. // re-install signal handler
  348. install_signal_handler();
  349. // Call the s_init method for _tt_mp. This will
  350. // cause the initial server session to be initiated
  351. // (ie. setup for rpc servicing and advertising our
  352. // address to tooltalk clients).
  353. status = _tt_s_mp->s_init();
  354. // now we check startup status, if we found another
  355. // session running then we return status=2. For other
  356. // errors we return status=1. (See auto-start code in
  357. // mp_session.cc in _Tt_session::init)
  358. switch (status) {
  359. case TT_OK:
  360. // rpc servicing has been initiated. Now we
  361. // can continue the initialization process.
  362. // This process is done this way because we
  363. // want to set up rpc servicing as soon as
  364. // possible so that clients can begin
  365. // contacting ttsession (they won't get
  366. // replies back until we're done with
  367. // initialization but that's ok).
  368. if (print_sessid) {
  369. // write our session id to a pipe that
  370. // was set up by our parent.
  371. sprintf(session_buf,"%s\n",
  372. (char *)(_tt_mp->initial_session->address_string()));
  373. write(ds_fds[1], session_buf, 255);
  374. }
  375. // initialize ptypes/otypes
  376. if (! init_types()) {
  377. // init_types() has emitted diagnostic
  378. exit(1);
  379. }
  380. // if we are running as a child ttsession then
  381. // we're now at a point where we're ready to
  382. // start servicing clients so kill off our
  383. // parent.
  384. if (background_mode) {
  385. // now were ready to accept requests so
  386. // kill the parent app.
  387. kill(getppid(), SIGTERM);
  388. }
  389. break;
  390. case TT_ERR_SESSION:
  391. // couldn't initialize because there's already
  392. // a ttsession running in our session scope.
  393. exit(2);
  394. case TT_ERR_NOMP:
  395. exit(1);
  396. break;
  397. default:
  398. _tt_syslog( errstr, LOG_ERR,
  399. "_Tt_s_session::s_init(): %d (%s)!",
  400. status, _tt_enumname(status));
  401. exit(1);
  402. }
  403. } else {
  404. // We're running as a parent ttsession, and we will
  405. // not be managing a ToolTalk session. Wait for our
  406. // child ttsession to either exit or kill us off with
  407. // a SIGTERM indicating it's ready.
  408. if (waitpid(forked_pid, &ch_status, 0) < 0) {
  409. //
  410. // Our signal handler should have called exit()!
  411. //
  412. _tt_syslog( errstr, LOG_ERR, "wait(): %m" );
  413. exit(1);
  414. }
  415. // if the wait returns then child ttsession must have
  416. // died abnormally. Return the status returned by the
  417. // child process.
  418. if (WIFEXITED(ch_status)) {
  419. // An exit status==2 is returned if the child
  420. // ttsession already found a session that is
  421. // active so we avoid printing out an error
  422. // message in this case.
  423. int exitStatus = WEXITSTATUS(ch_status);
  424. if (exitStatus != 2) {
  425. _tt_syslog( errstr, LOG_ERR,
  426. catgets( _ttcatd, 3, 8,
  427. "child ttsession exited"
  428. " with status %d" ),
  429. exitStatus );
  430. }
  431. exit(exitStatus);
  432. } else if (WIFSIGNALED(ch_status)) {
  433. _tt_syslog( errstr, LOG_ERR,
  434. catgets( _ttcatd, 3, 9,
  435. "child ttsession exited due "
  436. "to signal %d%s" ),
  437. WTERMSIG(ch_status),
  438. WCOREDUMP(ch_status) ?
  439. catgets( _ttcatd, 3, 10,
  440. " (core dumped)" )
  441. : "" );
  442. exit(1);
  443. } else {
  444. _tt_syslog( errstr, LOG_ERR,
  445. catgets( _ttcatd, 3, 11,
  446. "child ttsession neither "
  447. "exited nor was signaled!" ));
  448. exit(1);
  449. }
  450. }
  451. //
  452. // if we're in a process-tree session then fork the requested
  453. // root process (contained in "cmd"). This process will then
  454. // be monitored by the signal handler such that if it exits
  455. // then the signal handler will also abort the tooltalk
  456. // session.
  457. //
  458. if (cmd != (char *)0 &&
  459. _tt_mp->initial_session->env() == _TT_ENV_PROCESS_TREE) {
  460. int i;
  461. switch(forked_pid = fork()) {
  462. case -1:
  463. _tt_syslog( errstr, LOG_ERR, "fork(): %m" );
  464. exit(1);
  465. case 0:
  466. maxfds = _tt_getdtablesize();
  467. for (i = 3; i < maxfds; i++) {
  468. close(i);
  469. }
  470. _tt_restoredtablesize();
  471. signal(SIGHUP, SIG_IGN);
  472. execvp(cmd,
  473. cargv);
  474. _tt_syslog( errstr, LOG_ERR, "execvp(): %m" );
  475. exit(1);
  476. break;
  477. default:
  478. #if !defined(OPT_BSD_WAIT)
  479. child_waited_for = waitpid(-1, 0, WNOHANG);
  480. #else
  481. child_waited_for = wait3(&ch_status, WNOHANG, 0);
  482. #endif
  483. if (child_waited_for < 0) {
  484. _tt_syslog( errstr, LOG_ERR, "waitpid(): %m" );
  485. if (errno == ECHILD) {
  486. exit(1);
  487. }
  488. } else if (child_waited_for == forked_pid) {
  489. //
  490. // XXX This really cannot happen here,
  491. // because we handle SIGCHLD, so this
  492. // all happens in sig_handler()
  493. //
  494. int xstat = child_exit_status(
  495. child_waited_for, ch_status );
  496. if (xstat >= 0) {
  497. exit( xstat );
  498. }
  499. }
  500. break;
  501. }
  502. }
  503. if ((! background_mode) && (print_sessid)) {
  504. printf("%s\n",
  505. (char *)_tt_mp->initial_session->address_string());
  506. fflush(stdout);
  507. }
  508. #ifdef OPT_XTHREADS
  509. // Set the global lock. This basically locks out the init_self
  510. // thread until it is given permission to proceed. Locks are
  511. // given up just before RPC calls and upon thread exits.
  512. // Only this initial call should use mutex_lock as opposed
  513. // to _tt_global->grab_mutex, because here we do not want
  514. // to wait on the condition variable here.
  515. _tt_global->grab_mutex();
  516. // Initialize as a client of ourself. Ignore failure.
  517. xthread_fork((void *(*)(void *)) init_self, NULL);
  518. #else
  519. _tt_s_mp->init_self();
  520. #endif
  521. //
  522. // main service loop. We basically check for any programs we
  523. // forked exiting, check for flags set by the signal handler
  524. // (_tt_s_mp->exit_main_loop means exit out of rpc servicing,
  525. // signal_types_changed means we got a signal to re-read the
  526. // types database). If no signal flags were set or programs
  527. // exited, then we just invoke the _Tt_s_mp::main_loop method
  528. // to service rpc requests.
  529. //
  530. if (background_mode) {
  531. _tt_syslog( errstr, LOG_ERR,
  532. catgets( _ttcatd, 3, 12, "starting" ));
  533. // We are in daemon mode, so error output goes to syslog.
  534. errstr = 0;
  535. }
  536. while (1) {
  537. _tt_s_mp->exit_main_loop = 0;
  538. if (_tt_s_mp->fout != _tt_s_mp->fin) {
  539. notify_start_failure();
  540. }
  541. _tt_s_mp->main_loop();
  542. if (_tt_s_mp->xfd == -2) {
  543. // X server exited
  544. break;
  545. }
  546. //
  547. // exit from main_loop method is the result of
  548. // a signal (see sig_handler below)
  549. //
  550. if (signal_types_changed) {
  551. if (init_types()) {
  552. _tt_syslog( errstr, LOG_ERR,
  553. catgets( _ttcatd, 3, 13,
  554. "have re-read types"));
  555. } else {
  556. _tt_syslog( errstr, LOG_ERR,
  557. catgets( _ttcatd, 3, 14,
  558. "error in types; "
  559. "keeping old types" ));
  560. }
  561. signal_types_changed = 0;
  562. }
  563. if (signal_toggle_trace) {
  564. int was_on = tt_trace_control( -1 );
  565. _tt_syslog( errstr, LOG_ERR,
  566. "tt_trace_control( %d )", !was_on );
  567. signal_toggle_trace = 0;
  568. }
  569. if (_tt_s_mp->fout != _tt_s_mp->fin) {
  570. notify_start_failure();
  571. }
  572. }
  573. delete _tt_mp;
  574. exit(0);
  575. }
  576. #ifdef OPT_XTHREADS
  577. static void init_self()
  578. {
  579. _tt_s_mp->init_self();
  580. xthread_exit(0);
  581. }
  582. #endif
  583. //
  584. // This routine is called whenever _tt_s_mp->fin is not equal to
  585. // _tt_s_mp->fout (see comment for failed_procs above). This condition
  586. // signals that an asynchronous signal from the system came in telling us
  587. // that a child process exited. What we need to do is search the list of
  588. // ptypes for ptypes that are in the process of launching (see
  589. // _Tt_ptype::launch). If we find one whose start pid matches one of the
  590. // pids in the failed_procs array then we invoke the
  591. // _Tt_ptype::launch_failed method to arrange for the _Tt_ptype object to
  592. // handle this condition. The reason that this launch failure is special
  593. // is that a ptype that is in the process of being launched may not have
  594. // gotten far enough to launch a process that connects with ttsession so
  595. // the only mechanism we have to detect the failure is that the process
  596. // exited. What this means is that a process in a ptype's start string
  597. // cannot exit until it either connects with ttsession and replies to its
  598. // start message or until a process it launches does so.
  599. //
  600. void notify_start_failure()
  601. {
  602. // one of the starting ptypes failed to start.
  603. // Find which one it was and fail all the
  604. // messages waiting for it.
  605. // XXX: there should be better data-structure
  606. // support so we wouldn't have to iterate
  607. // through all the ptypes.
  608. _Tt_ptype_table_cursor ptypes;
  609. int ptype_found;
  610. while (_tt_s_mp->fout != _tt_s_mp->fin) {
  611. ptypes.reset(_tt_s_mp->ptable);
  612. ptype_found = 0;
  613. while (!ptype_found && ptypes.next()) {
  614. if (failed_procs[_tt_s_mp->fout]==ptypes->start_pid()) {
  615. if (ptypes->launching()) {
  616. ptypes->launch_failed();
  617. ptype_found = 1;
  618. }
  619. }
  620. }
  621. _tt_s_mp->fout++;
  622. if (_tt_s_mp->fout == MAXPIDS) {
  623. _tt_s_mp->fout = 0;
  624. }
  625. }
  626. }
  627. //
  628. // Install sig_handler as the handler for all the signals it handles.
  629. //
  630. void
  631. install_signal_handler()
  632. {
  633. _Tt_string err = "_tt_sigset(SIG";
  634. if (_tt_sigset(SIGHUP, &sig_handler) == 0) {
  635. _tt_syslog( errstr, LOG_WARNING, err.cat("HUP)"));
  636. }
  637. if (_tt_sigset(SIGTERM, &sig_handler) == 0) {
  638. _tt_syslog( errstr, LOG_WARNING, err.cat("TERM)") );
  639. }
  640. if (_tt_sigset(SIGINT, &sig_handler) == 0) {
  641. _tt_syslog( errstr, LOG_WARNING, err.cat("INT)") );
  642. }
  643. if (_tt_sigset(SIGUSR1, &sig_handler) == 0) {
  644. _tt_syslog( errstr, LOG_WARNING, err.cat("USR1)") );
  645. }
  646. if (_tt_sigset(SIGUSR2, &sig_handler) == 0) {
  647. _tt_syslog( errstr, LOG_WARNING, err.cat("USR2)") );
  648. }
  649. if (_tt_sigset(SIGCHLD, &sig_handler) == 0) {
  650. _tt_syslog( errstr, LOG_WARNING, err.cat("CHLD)") );
  651. }
  652. if (_tt_sigset(SIGPIPE, &sig_handler) == 0) {
  653. _tt_syslog( errstr, LOG_WARNING, err.cat("PIPE)") );
  654. }
  655. }
  656. //
  657. // Reads in the ptype/otype database from the XDR (or CE) database.
  658. // Once the types are read in from the database the types are installed
  659. // via the appropiate _Tt_s_mp methods install_ptable and install_otable.
  660. // Keep a pointer to the _Tt_typedb structure so we can merge in
  661. // more types later on via tt_session_types_load.
  662. //
  663. int
  664. init_types()
  665. {
  666. Tt_status err;
  667. #ifdef OPT_CLASSING_ENGINE
  668. _Tt_typedb::ce2xdr();
  669. #endif
  670. _tt_s_mp->tdb = new _Tt_typedb();
  671. if (option_classing_engine) {
  672. err = _tt_s_mp->tdb->init_ce();
  673. if (err != TT_OK) {
  674. if (0==getenv("OPENWINHOME")) {
  675. _tt_syslog( errstr, LOG_ERR,
  676. catgets( _ttcatd, 3, 15,
  677. "$OPENWINHOME not set"));
  678. }
  679. return(0);
  680. }
  681. } else {
  682. err = _tt_s_mp->tdb->init_xdr();
  683. switch (err) {
  684. case TT_OK:
  685. case TT_ERR_NO_MATCH:
  686. case TT_ERR_DBCONSIST:
  687. case TT_ERR_PATH:
  688. break;
  689. default:
  690. _tt_syslog( errstr, LOG_ERR,
  691. "_Tt_typedb::init_xdr(): %s",
  692. _tt_enumname(err));
  693. }
  694. if (err != TT_OK) {
  695. return(0);
  696. }
  697. }
  698. _tt_s_mp->install_ptable(_tt_s_mp->tdb->ptable);
  699. _tt_s_mp->install_otable(_tt_s_mp->tdb->otable);
  700. return(1);
  701. }
  702. //
  703. // Prints out a usage string and exits.
  704. //
  705. void
  706. print_usage_and_exit()
  707. {
  708. _tt_syslog( errstr, LOG_ERR, "%s%s%s%s%s",
  709. catgets( _ttcatd, 3, 16,
  710. "\nUsage: ttsession [-a cookie|unix|des][-d display][-spStvhNX" ),
  711. #if defined(OPT_CLASSING_ENGINE)
  712. "E",
  713. #else
  714. "",
  715. #endif
  716. catgets( _ttcatd, 3, 17,
  717. "][-c command]\n"
  718. " -c [command] start a process tree session, and run command in it.\n"
  719. " Subsequent options are passed to command. Default: $SHELL\n"
  720. " -p start a process tree session, and print its id\n"
  721. " -d display start an X session on display\n"
  722. "\n"
  723. " -a cookie|unix|des set server authentication level\n"
  724. " -s silent. Don't print out any warnings\n"
  725. " -S don't fork into the background\n"
  726. " -N maximize the number of clients allowed\n"
  727. " -t turn on message tracing\n"
  728. " -X use XDR databases for static types (default)\n" ),
  729. #if defined(OPT_CLASSING_ENGINE)
  730. catgets( _ttcatd, 3, 18,
  731. " -E use Classing Engine for static types\n" ),
  732. #else
  733. "",
  734. #endif
  735. catgets( _ttcatd, 3, 19,
  736. "\n"
  737. " -v print out version number\n"
  738. " -h print out this message\n"
  739. "\n"
  740. "Signal interface:\n"
  741. " kill -USR1 ttsession_pid toggle message tracing\n"
  742. " kill -USR2 ttsession_pid re-read static types" ) );
  743. exit(1);
  744. }
  745. //
  746. // Global signal handler for ttsession. All signals are handled by this
  747. // function (ie. no signal handlers should be defined in any other files)
  748. //
  749. void
  750. sig_handler(int sig)
  751. {
  752. int intrs = 100;
  753. pid_t child_pid;
  754. _Tt_wait_status status;
  755. switch (sig) {
  756. case SIGPIPE:
  757. // usually the result of a write on a broken tcp
  758. // socket. Default action is to ignore it.
  759. break;
  760. case SIGHUP:
  761. break;
  762. case SIGCHLD:
  763. // a child process has exited. If the process that
  764. // exited is the root process of a process-tree
  765. // session then we exit. Otherwise, it is possibly a
  766. // ptype that we launched so we record its pid in the
  767. // failed_procs list (see comment above for
  768. // failed_procs).
  769. #if !defined(OPT_BSD_WAIT)
  770. // XXX: the sysv code should do the same loop as
  771. // below.
  772. child_pid = waitpid(-1, &status, WNOHANG);
  773. #else
  774. // we do an asynchronous wait on the child to get its
  775. // pid. However the wait3 call can be interrupted and
  776. // return an EINTR so we keep trying for a bounded
  777. // amount of time.
  778. while (((child_pid = wait3(&status, WNOHANG, 0)) == -1)
  779. && errno == EINTR) {
  780. if (! intrs--) {
  781. _tt_syslog( errstr, LOG_ERR, "wait3(): %m" );
  782. break;
  783. }
  784. }
  785. #endif // OPT_BSD_WAIT
  786. // check for the child pid being the root process of a
  787. // process-tree id and exit if it is. Otherwise record
  788. // the pid in the failed_procs list and set
  789. // _tt_s_mp->exit_main_loop to 1 to signal the main
  790. // event loop to break out of rpc servicing to handle
  791. // this condition.
  792. if (child_pid > 0) {
  793. int status2exit = child_exit_status(child_pid, status);
  794. int isdead = status2exit >= 0;
  795. if (isdead) {
  796. if (child_pid == forked_pid) {
  797. // calling free in a sig handler is a no-no
  798. // delete _tt_mp;
  799. exit(status2exit);
  800. }
  801. else
  802. #ifdef OPT_XTHREADS
  803. if(child_pid !=
  804. _tt_s_mp->garbage_collector_pid)
  805. #endif
  806. {
  807. failed_procs[_tt_s_mp->fin] = child_pid;
  808. _tt_s_mp->fin++;
  809. if (_tt_s_mp->fin == MAXPIDS) {
  810. _tt_s_mp->fin = 0;
  811. }
  812. }
  813. }
  814. _tt_s_mp->exit_main_loop = 1;
  815. return;
  816. }
  817. _tt_syslog( errstr, LOG_WARNING, "waitpid(): %m");
  818. break;
  819. case SIGTERM:
  820. // this signal is sent by a forked ttsession when it
  821. // is ready to start servicing clients. It is our
  822. // signal to exit. For the special case of a "dialin"
  823. // session we print out the child session's id.
  824. if ((background_mode) && (forked_pid > 0)) {
  825. if (print_sessid) {
  826. memset(session_buf, 0, 255);
  827. read(ds_fds[0], session_buf, 255 - 1);
  828. printf("%s", session_buf);
  829. }
  830. // this is the signal from the forked
  831. // ttsession that we should exit.
  832. exit(0);
  833. }
  834. // The child ttsession falls through to clean itself up
  835. case SIGINT:
  836. _tt_syslog( errstr, LOG_ERR,
  837. catgets( _ttcatd, 3, 20, "exiting" ));
  838. // if this is a process tree system, let our kid know
  839. // it's time to depart. It's important to allow the
  840. // process tree root process to exit beforehand so
  841. // that the controlling terminal will get properly
  842. // reassigned. Otherwise, the SIGINT will cause the
  843. // entire process hierarchy that has the same
  844. // controlling terminal to exit (so for example your
  845. // shelltool window would die because ttsession was
  846. // killed in process-tree mode).
  847. if (forked_pid > 0
  848. && 0 == kill(forked_pid, SIGINT)) {
  849. // Wait for a decent interval to give him a chance
  850. // to clean up
  851. int i;
  852. for (i=0; i<10; i++) {
  853. sleep(1);
  854. if (forked_pid ==
  855. waitpid(forked_pid, 0, WNOHANG)) {
  856. break;
  857. }
  858. }
  859. if (i==10) {
  860. // Won't go away, eh? Time to get tough.
  861. if (0 == kill(forked_pid, SIGKILL)) {
  862. waitpid(forked_pid, 0, 0);
  863. }
  864. }
  865. }
  866. // calling free in a sig handler is a no-no
  867. // delete _tt_mp;
  868. exit(1);
  869. break;
  870. case SIGUSR1:
  871. // signal to toggle message tracing
  872. signal_toggle_trace = 1;
  873. break;
  874. case SIGTYPES:
  875. // signal to reread types database
  876. _tt_s_mp->exit_main_loop = 1;
  877. signal_types_changed = 1;
  878. break;
  879. default:
  880. break;
  881. }
  882. }