PageRenderTime 60ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/cde/programs/dtexec/Main.c

https://bitbucket.org/tifan/cde
C | 1636 lines | 841 code | 193 blank | 602 comment | 243 complexity | 1563bb3d24912f74a7e26605f3f6e774 MD5 | raw file
Possible License(s): LGPL-2.1, IPL-1.0, 0BSD
  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 librararies 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. /*
  24. * (c) Copyright 1995 Digital Equipment Corporation.
  25. * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
  26. * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
  27. * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
  28. * (c) Copyright 1993, 1994, 1995 Novell, Inc.
  29. * (c) Copyright 1995 FUJITSU LIMITED.
  30. * (c) Copyright 1995 Hitachi.
  31. */
  32. /******************************************************************************
  33. *
  34. * File: Main.c
  35. * RCS: $TOG: Main.c /main/9 1999/09/20 15:36:11 mgreess $
  36. * Package: dtexec for CDE 1.0
  37. *
  38. *****************************************************************************/
  39. #define SPINBLOCK if (getenv("_DTEXEC_DEBUG")) {int i; i=1; while(i) i=1;}
  40. /*
  41. * _DTEXEC_NLS16 controls whether I18N code should be used. As of 7/94,
  42. * libDtSvc should be the only one using dtexec, and the command line
  43. * and parsing code are I18N insensitive, and thats o.k.
  44. *
  45. * If turned on, some routines from DtSvc/DtUtil2/DtNlUtils.c will be
  46. * needed.
  47. */
  48. #undef _DTEXEC_NLS16
  49. #include <fcntl.h>
  50. #include <sys/stat.h>
  51. #include <signal.h>
  52. #include <stdio.h>
  53. #include <errno.h>
  54. #include <sys/wait.h>
  55. #include "osdep.h" /* select(2) mask width and bit manipulation macros */
  56. #include <Tt/tt_c.h>
  57. #include <locale.h>
  58. #include <Dt/MsgLog.h>
  59. /*
  60. * From Dt/ActionP.h - never change since these are in effect protocol
  61. * codes! See Dt/ActionP.h for more details.
  62. */
  63. #ifndef _ActionP_h
  64. #define _DtActCHILD_UNKNOWN (1<<0) /* 1 - child status unknown */
  65. #define _DtActCHILD_PENDING_START (1<<1) /* 2 - child start pending */
  66. #define _DtActCHILD_ALIVE_UNKNOWN (1<<2) /* 4 - child alive but unknown*/
  67. #define _DtActCHILD_ALIVE (1<<3) /* 8 - child alive and well */
  68. #define _DtActCHILD_DONE (1<<4) /* 16 - child done */
  69. #define _DtActCHILD_FAILED (1<<5) /* 32 - child failed */
  70. #define _DtActCHILD_CANCELED (1<<6) /* 64 - child canceled */
  71. #endif /* _ActionP_h */
  72. #define MAX_EXEC_ARGS 1000 /* Maximum number of arguments for */
  73. /* execvp call. */
  74. #define True 1
  75. #define False 0
  76. #define PERM_TERM 1
  77. #define TRANSIENT 2
  78. #define SHORT 3
  79. /*
  80. * Triggered by a SIGCLD, the shutdown sequence.
  81. */
  82. #define SDP_DONE_STARTING 1
  83. #define SDP_DONE_REPLY_WAIT 2
  84. #define SDP_DONE_REPLIED 3
  85. #define SDP_DONE_PANIC_CLEANUP 4
  86. #define SDP_FINAL_LINGER 5
  87. /*
  88. * Timeout period in milliseconds for select() when we are rediscovering
  89. * signals and engage in a shutdown process. More often than not, we
  90. * will services signals out of select() immediately. The only interesting
  91. * moment is waiting for a Done(Reply).
  92. */
  93. #define SHORT_SELECT_TIMEOUT 20
  94. /*
  95. * External system calls:
  96. */
  97. extern pid_t fork ();
  98. extern int execvp ();
  99. extern pid_t wait ();
  100. extern int atoi ();
  101. extern void _exit ();
  102. extern unsigned int sleep ();
  103. extern void exit ();
  104. extern char *getenv();
  105. /*
  106. * Local func protos
  107. */
  108. void DoneRequest(int doneCode);
  109. /*
  110. * Global variables.
  111. */
  112. struct timeval startTimeG;
  113. struct timezone zoneG;
  114. int requestTypeG;
  115. pid_t childPidG; /* PID of child we fork/exec */
  116. long waitTimeG; /* -open setting */
  117. char *dtSvcProcIdG; /* TT Proc ID of our caller */
  118. int dtSvcInvIdG; /* Invocation ID that our caller manages us by*/
  119. int dtSvcChildIdG; /* Child ID that our caller manages us by */
  120. int tmpFileCntG; /* tmp file count */
  121. char **tmpFilesG; /* tmp files we might need to unlink */
  122. fd_set allactivefdsG; /* all possible fildes of interest. */
  123. /* - mskcnt generated from osdep.h */
  124. int rediscoverSigCldG; /* if a SIGCLD goes off */
  125. int rediscoverUrgentSigG; /* if a SIGTERM, SIGHUP or SIGQUIT goes off */
  126. int shutdownPhaseG; /* shutdown progress state variable */
  127. int ttfdG; /* tooltalk fildes */
  128. int errorpipeG[2]; /* dtexec <--< child stderr pipe */
  129. /******************************************************************************
  130. *
  131. * Minaturized versions of tttk_*() routines. Used so we don't have to
  132. * pull in tttk which in turn would pull in Xt.
  133. *
  134. *****************************************************************************/
  135. char *dtexec_Tttk_integer = "integer";
  136. char *dtexec_Tttk_message_id = "messageID";
  137. Tt_message
  138. dtexec_tttk_message_create(
  139. Tt_message context,
  140. Tt_class theClass,
  141. Tt_scope theScope,
  142. const char *handler,
  143. const char *op,
  144. Tt_message_callback callback
  145. )
  146. {
  147. Tt_message msg;
  148. Tt_address address;
  149. Tt_status status;
  150. msg = tt_message_create();
  151. status = tt_ptr_error( msg );
  152. if (status != TT_OK) {
  153. return msg;
  154. }
  155. status = tt_message_class_set( msg, theClass );
  156. if (status != TT_OK) {
  157. return (Tt_message)tt_error_pointer( status );
  158. }
  159. status = tt_message_scope_set( msg, theScope );
  160. if (status != TT_OK) {
  161. return (Tt_message)tt_error_pointer( status );
  162. }
  163. address = TT_PROCEDURE;
  164. if (handler != 0) {
  165. status = tt_message_handler_set( msg, handler );
  166. if (status != TT_OK) {
  167. return (Tt_message)tt_error_pointer( status );
  168. }
  169. address = TT_HANDLER;
  170. }
  171. status = tt_message_address_set( msg, address );
  172. if (status != TT_OK) {
  173. return (Tt_message)tt_error_pointer( status );
  174. }
  175. if (op != 0) {
  176. status = tt_message_op_set( msg, op );
  177. if (status != TT_OK) {
  178. return (Tt_message)tt_error_pointer( status );
  179. }
  180. }
  181. if (callback != 0) {
  182. status = tt_message_callback_add( msg, callback );
  183. if (status != TT_OK) {
  184. return (Tt_message)tt_error_pointer( status );
  185. }
  186. }
  187. return msg;
  188. }
  189. Tt_status
  190. dtexec_tttk_message_destroy(
  191. Tt_message msg
  192. )
  193. {
  194. Tt_status status;
  195. status = tt_message_destroy(msg);
  196. return status;
  197. }
  198. int
  199. dtexec_tttk_message_am_handling(
  200. Tt_message msg
  201. )
  202. {
  203. char *handler;
  204. int am_handling;
  205. if (tt_message_class( msg ) != TT_REQUEST) {
  206. return 0;
  207. }
  208. if (tt_message_state( msg ) != TT_SENT) {
  209. return 0;
  210. }
  211. handler = tt_message_handler( msg );
  212. am_handling = 0;
  213. if ((tt_ptr_error( handler ) == TT_OK) && (handler != 0)) {
  214. am_handling = 1;
  215. }
  216. tt_free( handler );
  217. return am_handling;
  218. }
  219. Tt_status
  220. dtexec_tttk_message_abandon(
  221. Tt_message msg
  222. )
  223. {
  224. int fail;
  225. Tt_status status;
  226. if (dtexec_tttk_message_am_handling( msg )) {
  227. fail = 0;
  228. if (tt_message_address( msg ) == TT_HANDLER) {
  229. fail = 1;
  230. } else if (tt_message_status( msg ) == TT_WRN_START_MESSAGE) {
  231. fail = 1;
  232. }
  233. if (fail) {
  234. if (tt_message_class( msg ) == TT_REQUEST) {
  235. tt_message_status_set(msg, TT_DESKTOP_ENOTSUP);
  236. status = tt_message_fail( msg );
  237. dtexec_tttk_message_destroy( msg );
  238. }
  239. else {
  240. status = dtexec_tttk_message_destroy( msg );
  241. }
  242. } else {
  243. tt_message_status_set( msg, TT_DESKTOP_ENOTSUP );
  244. status = tt_message_reject( msg );
  245. dtexec_tttk_message_destroy( msg );
  246. }
  247. } else {
  248. status = dtexec_tttk_message_destroy( msg );
  249. }
  250. return status;
  251. }
  252. /******************************************************************************
  253. *
  254. * Help - print the usage and exit.
  255. *
  256. *****************************************************************************/
  257. static void
  258. Help(
  259. char *argv[] )
  260. {
  261. (void) fprintf (stderr, "Usage:\n");
  262. (void) fprintf (stderr, "\t%s [-options ...] cmd [cmd arg ...]\n", argv[0]);
  263. (void) fprintf (stderr, "\n");
  264. (void) fprintf (stderr, "where options include:\n");
  265. (void) fprintf (stderr, "\t-open open-option\n");
  266. (void) fprintf (stderr, "\t\t-1 (default) continue to execute after cmd terminates,\n");
  267. (void) fprintf (stderr, "\t\t thus keeping the terminal window open.\n");
  268. (void) fprintf (stderr, "\t\t 0 exit as soon as cmd terminates, thus allowing\n");
  269. (void) fprintf (stderr, "\t\t the terminal window to close.\n");
  270. (void) fprintf (stderr, "\t\t n continue to execute if cmd terminates within n\n");
  271. (void) fprintf (stderr, "\t\t seconds of starting.\n");
  272. (void) fprintf (stderr, "\t-ttprocid procid\n");
  273. (void) fprintf (stderr, "\t-tmp tmpfile [-tmp tmpfile ...]\n");
  274. (void) fprintf (stderr, "\n");
  275. _exit(0);
  276. }
  277. /******************************************************************************
  278. *
  279. * PanicSignal - see InitializeSignalHandling()
  280. *
  281. *****************************************************************************/
  282. static void
  283. #if defined(__aix) || defined (__osf__)
  284. PanicSignal(int s)
  285. #else
  286. PanicSignal(void)
  287. #endif /* __aix || __osf__ */
  288. {
  289. int i;
  290. /*
  291. * Crude, but let libDtSvc know we've been forced down.
  292. * Atleast libDtSvc will get a hint and know to cleanup.
  293. */
  294. if (dtSvcProcIdG)
  295. DoneRequest(_DtActCHILD_FAILED);
  296. if (!dtSvcProcIdG) {
  297. /*
  298. * We cannot talk with caller, so do cleanup
  299. * of tmp files.
  300. */
  301. for (i = 0; i < tmpFileCntG; i++ ) {
  302. chmod( tmpFilesG[i], (S_IRUSR|S_IWUSR) );
  303. unlink( tmpFilesG[i] );
  304. }
  305. }
  306. _exit(0);
  307. }
  308. /******************************************************************************
  309. *
  310. * IgnoreSignal - see InitializeSignalHandling()
  311. *
  312. *****************************************************************************/
  313. static void
  314. #if defined(__aix) || defined (__osf__)
  315. IgnoreSignal(int i)
  316. #else
  317. IgnoreSignal(void)
  318. #endif /* __aix || __osf__ */
  319. {
  320. /*
  321. * If the child is still in the same process group, it should be
  322. * getting the same signal too.
  323. */
  324. if (rediscoverSigCldG) {
  325. if (shutdownPhaseG == SDP_FINAL_LINGER) {
  326. /*
  327. * We were shutdown long ago and lingering, so go ahead
  328. * and exit now.
  329. */
  330. _exit(0);
  331. }
  332. else {
  333. /*
  334. * Still shutting down, so flip requestTypeG so that dtexec
  335. * will not linger when the shutdown process completes.
  336. */
  337. requestTypeG = TRANSIENT;
  338. }
  339. }
  340. else {
  341. /*
  342. * If and when the child does repond to the signal we are
  343. * ignoring for now, don't allow dtexec to linger.
  344. */
  345. requestTypeG = TRANSIENT;
  346. }
  347. }
  348. /******************************************************************************
  349. *
  350. * UrgentSignal - see InitializeSignalHandling()
  351. *
  352. *****************************************************************************/
  353. static void
  354. #if defined(__aix) || defined (__osf__)
  355. UrgentSignal(int i)
  356. #else
  357. UrgentSignal(void)
  358. #endif /* __aix || __osf__ */
  359. {
  360. /*
  361. * Set global so the central control point ( select() ) will
  362. * rediscover the urgent signal.
  363. */
  364. rediscoverUrgentSigG = 1;
  365. /*
  366. * If the child is still in the same process group, it should be
  367. * getting the same signal too.
  368. */
  369. if (rediscoverSigCldG) {
  370. if (shutdownPhaseG == SDP_FINAL_LINGER) {
  371. /*
  372. * We were shutdown long ago and lingering, so go ahead
  373. * and exit now.
  374. */
  375. _exit(0);
  376. }
  377. else {
  378. /*
  379. * Still shutting down, so flip requestTypeG so that dtexec
  380. * will not linger when the shutdown process completes.
  381. */
  382. requestTypeG = TRANSIENT;
  383. }
  384. }
  385. else {
  386. /*
  387. * If and when the child does repond to the signal we are
  388. * ignoring for now, don't allow dtexec to linger.
  389. *
  390. * This is mildly different than the IgnoreSignal case because
  391. * there is a timeout associated with UrgentSignals.
  392. */
  393. requestTypeG = TRANSIENT;
  394. }
  395. }
  396. /******************************************************************************
  397. *
  398. * SigCld - see InitializeSignalHandling()
  399. *
  400. *****************************************************************************/
  401. static void
  402. #if defined(__aix) || defined (__osf__)
  403. SigCld(int i)
  404. #else
  405. SigCld(void)
  406. #endif /* __aix || __osf__ */
  407. {
  408. int exitStatus;
  409. pid_t pid;
  410. /*
  411. * Query why the SIGCLD happened - a true termination or just a stopage.
  412. * We only care about terminations.
  413. */
  414. pid = wait(&exitStatus);
  415. if (pid == -1) {
  416. if (errno == ECHILD) {
  417. /*
  418. * No child found with wait(), so sure, act like we did
  419. * see a SIGCLD.
  420. */
  421. rediscoverSigCldG = 1;
  422. }
  423. }
  424. else if (!WIFSTOPPED(exitStatus)) {
  425. /*
  426. * The SIGCLD was *not* the result of being stopped, so the child
  427. * has indeed terminated.
  428. */
  429. rediscoverSigCldG = 1;
  430. }
  431. }
  432. /******************************************************************************
  433. *
  434. * InitializeSignalHandling - Set up the signal catchers.
  435. *
  436. * Keep this code in sync with fork/exec code so as to NOT pass
  437. * these catchers onto our child.
  438. *
  439. * "Ignore"
  440. * 1. if already SIGCLD
  441. * A. if SDP_FINAL_LINGER, _exit(0)
  442. * B. else set requestTypeG to TRANSIENT
  443. * 2. else ignore signal
  444. * 3. select-loop-spin
  445. *
  446. * comment: if fact we don't ignore the signal, but instead let the
  447. * child control the pace of the response to the signal.
  448. *
  449. * "Urgent"
  450. * 1. if already SIGCLD
  451. * A. if SDP_FINAL_LINGER, _exit(0)
  452. * B. else set requestTypeG to TRANSIENT
  453. * 2. wait 5 seconds hoping to goto "SIGCLD" path from select-loop-spin
  454. * 3. else do "Panic" path after 5 seconds
  455. *
  456. * "SIGCLD"
  457. * 1. send Done(Request)
  458. * 2. wait for Done(Reply) in select-loop-spin
  459. * 3. send Quit(Reply)
  460. * 4. cleanup
  461. * 5. FinalLinger()
  462. *
  463. * "Panic"
  464. * 1. send Done(Request)
  465. * 2. send Quit(Reply)
  466. * 3. cleanup
  467. * 4. _exit(0)
  468. *
  469. * "Default"
  470. * 1. default signal action
  471. *
  472. *****************************************************************************/
  473. static void
  474. InitializeSignalHandling( void )
  475. {
  476. long oldMask;
  477. struct sigaction svec;
  478. /*
  479. * "Graceful Signal" handlers
  480. * - SIGCLD for normal child termination - best case.
  481. */
  482. sigemptyset(&svec.sa_mask);
  483. svec.sa_flags = 0;
  484. svec.sa_handler = SigCld;
  485. (void) sigaction(SIGCLD, &svec, (struct sigaction *) NULL);
  486. /*
  487. * "Urgent Signal" handlers
  488. * - SIGTERM for standard kill(1)
  489. *
  490. * We treat these signals in a special way. When the signal comes
  491. * in, we hope to see the child respond with a SIGCLD within 5
  492. * seconds, else we act like the SIGTERM was for us and go down.
  493. */
  494. sigemptyset(&svec.sa_mask);
  495. svec.sa_flags = 0;
  496. svec.sa_handler = UrgentSignal;
  497. (void) sigaction(SIGTERM, &svec, (struct sigaction *) NULL);
  498. /*
  499. * "Panic Signal" handlers.
  500. * - SIGINT for BBA coverage.
  501. */
  502. sigemptyset(&svec.sa_mask);
  503. svec.sa_flags = 0;
  504. svec.sa_handler = PanicSignal;
  505. (void) sigaction(SIGINT, &svec, (struct sigaction *) NULL);
  506. /*
  507. * "Ignore Signal" handlers.
  508. * - SIGUSR1 - let child decide how to respond
  509. * - SIGUSR2 - let child decide how to respond
  510. * - SIGHUP - let child decide how to respond
  511. */
  512. sigemptyset(&svec.sa_mask);
  513. svec.sa_flags = 0;
  514. svec.sa_handler = IgnoreSignal;
  515. (void) sigaction(SIGUSR1, &svec, (struct sigaction *) NULL);
  516. (void) sigaction(SIGUSR2, &svec, (struct sigaction *) NULL);
  517. (void) sigaction(SIGHUP, &svec, (struct sigaction *) NULL);
  518. /*
  519. * "Default Signal" handlers.
  520. * - SIGQUIT - let core dump happen as expected. If done,
  521. * libDtSvc will never get a done notice.
  522. */
  523. }
  524. /******************************************************************************
  525. *
  526. * After all is said and done, enter FinalLinger which
  527. * will decide if and how long the associated terminal
  528. * emulator will stay up.
  529. *
  530. *****************************************************************************/
  531. void FinalLinger(void)
  532. {
  533. int exitStatus;
  534. struct timeval finalTime;
  535. /*
  536. * Make sure to reap child. The SIGCLD handler may have done
  537. * this already.
  538. */
  539. (void) wait(&exitStatus);
  540. if (requestTypeG == PERM_TERM)
  541. (void) sleep (99999999);
  542. else if (requestTypeG == TRANSIENT)
  543. (void) _exit (0);
  544. else {
  545. /*
  546. * Check the time stamps and either sleep forever or exit.
  547. */
  548. if ((gettimeofday (&finalTime, &zoneG)) == -1)
  549. (void) _exit (1);
  550. if ((finalTime.tv_sec - startTimeG.tv_sec) < waitTimeG)
  551. (void) sleep (99999999);
  552. else
  553. (void) _exit (0);
  554. }
  555. }
  556. /******************************************************************************
  557. *
  558. * ExecuteCommand -
  559. *
  560. *****************************************************************************/
  561. static int
  562. ExecuteCommand (
  563. char **commandArray)
  564. {
  565. int i, index1;
  566. int exitStatus;
  567. struct sigaction svec;
  568. for (index1 = 0; (index1 < 10) && ((childPidG = fork()) < 0); index1++) {
  569. /* Out of resources ? */
  570. if (errno != EAGAIN)
  571. break;
  572. /* If not out of resources, sleep and try again */
  573. (void) sleep ((unsigned long) 2);
  574. }
  575. if (childPidG < 0) {
  576. return (False);
  577. }
  578. if (childPidG == 0) {
  579. /*
  580. * Child Process.
  581. */
  582. /*
  583. * Hook stderr to error pipe back to parent.
  584. */
  585. if ((errorpipeG[0] != -1) && (errorpipeG[1] != -1)) {
  586. dup2(errorpipeG[1], 2);
  587. close(errorpipeG[0]);
  588. }
  589. /*
  590. * The child should have default behavior for all signals.
  591. */
  592. sigemptyset(&svec.sa_mask);
  593. svec.sa_flags = 0;
  594. svec.sa_handler = SIG_DFL;
  595. /* Normal */
  596. (void) sigaction(SIGCLD, &svec, (struct sigaction *) NULL);
  597. /* Urgent */
  598. (void) sigaction(SIGTERM, &svec, (struct sigaction *) NULL);
  599. /* Panic */
  600. (void) sigaction(SIGINT, &svec, (struct sigaction *) NULL);
  601. /* Ignore */
  602. (void) sigaction(SIGUSR1, &svec, (struct sigaction *) NULL);
  603. (void) sigaction(SIGUSR2, &svec, (struct sigaction *) NULL);
  604. (void) sigaction(SIGHUP, &svec, (struct sigaction *) NULL);
  605. for (i=3; i < FOPEN_MAX; i++) {
  606. if ( i != errorpipeG[1] )
  607. (void) fcntl (i, F_SETFD, 1);
  608. }
  609. (void) execvp(commandArray[0], commandArray);
  610. (void) fprintf (stderr, "Cannot execute \"%s\".\n", commandArray[0]);
  611. (void) _exit (1);
  612. }
  613. if (errorpipeG[1] != -1) {
  614. close(errorpipeG[1]);
  615. errorpipeG[1] = -1;
  616. }
  617. return (True);
  618. }
  619. /******************************************************************************
  620. *
  621. * ParseCommandLine
  622. *
  623. * Peel off options to dtexec. As soon as an argv[n] is not a valid
  624. * dtexec option, assume it is the start of the cmd line and return.
  625. *
  626. *****************************************************************************/
  627. static char **
  628. ParseCommandLine(
  629. int argc,
  630. char **argv )
  631. {
  632. char **argv2;
  633. char *tick1, *tick2;
  634. #ifdef _DTEXEC_NLS16
  635. int tmpi;
  636. #endif /* _DTEXEC_NLS16 */
  637. argv2 = (char **) argv;
  638. tmpFileCntG = 0;
  639. tmpFilesG = (char **) NULL;
  640. for (argc--, argv++; argc > 0; argc--, argv++) {
  641. if ( ! strcmp(argv[0] , "-open") ) {
  642. argc--; argv++;
  643. if ( argc == 0 ) Help( argv2 );
  644. waitTimeG = atoi (argv[0]);
  645. if (waitTimeG < 0)
  646. requestTypeG = PERM_TERM;
  647. else if (waitTimeG == 0)
  648. requestTypeG = TRANSIENT;
  649. else {
  650. requestTypeG = SHORT;
  651. }
  652. }
  653. else if ( ! strcmp(argv[0] , "-ttprocid") ) {
  654. argc--; argv++;
  655. if ( argc == 0 ) Help( argv2 );
  656. /*
  657. * Pull the -ttprocid argument apart for it's 3 components.
  658. * <libDtSvc's ProcId>_<Invocation Id>_<Child Id>
  659. */
  660. #ifdef _DTEXEC_NLS16
  661. tmpi = mblen(argv[0]);
  662. dtSvcProcIdG = (char *) malloc( tmpi + 1 );
  663. memcpy( dtSvcProcIdG, argv[0], tmpi );
  664. dtSvcProcIdG[tmpi] = NULL;
  665. #else
  666. dtSvcProcIdG = (char *) malloc( strlen(argv[0]) + 1 );
  667. strcpy( dtSvcProcIdG, argv[0] );
  668. #endif /* _DTEXEC_NLS16 */
  669. /*
  670. * Search from the end for underscore seperators.
  671. */
  672. #ifdef _DTEXEC_NLS16
  673. tick2 = (char *) Dt_strrchr( dtSvcProcIdG, '_' );
  674. #else
  675. tick2 = (char *) strrchr( dtSvcProcIdG, '_' );
  676. #endif /* _DTEXEC_NLS16 */
  677. if (tick2)
  678. *tick2 = NULL;
  679. #ifdef _DTEXEC_NLS16
  680. tick1 = (char *) Dt_strrchr( dtSvcProcIdG, '_' );
  681. #else
  682. tick1 = (char *) strrchr( dtSvcProcIdG, '_' );
  683. #endif /* _DTEXEC_NLS16 */
  684. if ( tick1 && tick2 ) {
  685. *tick1 = NULL;
  686. *tick2 = NULL;
  687. dtSvcInvIdG = atoi((char *) (tick1 + 1));
  688. dtSvcChildIdG = atoi((char *) (tick2 + 1));
  689. if ( !(dtSvcInvIdG && dtSvcChildIdG) ) {
  690. /*
  691. * Don't have two non-zero values, so we cannot use the
  692. * -ttprocid provided.
  693. */
  694. free(dtSvcProcIdG);
  695. dtSvcProcIdG = (char *) NULL;
  696. }
  697. }
  698. else {
  699. /*
  700. * Unable to find _ (underscore) seperators.
  701. */
  702. free(dtSvcProcIdG);
  703. dtSvcProcIdG = (char *) NULL;
  704. }
  705. }
  706. else if ( ! strcmp(argv[0] , "-tmp") ) {
  707. argc--; argv++;
  708. if ( argc == 0 ) Help( argv2 );
  709. tmpFileCntG++;
  710. tmpFilesG = (char **) realloc( (char *) tmpFilesG,
  711. tmpFileCntG * sizeof(char *) );
  712. tmpFilesG[tmpFileCntG-1] = argv[0];
  713. }
  714. else if ( ! strncmp(argv[0], "-h", 2) ) {
  715. Help( argv2 );
  716. /*
  717. * Technically we should see if a -ttprocid was given and
  718. * possibly send back a Done(Request).
  719. */
  720. (void) _exit (1);
  721. }
  722. else {
  723. return( argv );
  724. }
  725. }
  726. /*
  727. * No arguments to dtexec, so nothing to fork/exec.
  728. */
  729. return( (char **) NULL );
  730. }
  731. /******************************************************************************
  732. *
  733. * Shutdown Tooltalk connection.
  734. *
  735. *****************************************************************************/
  736. void DetachFromTooltalk(
  737. unsigned long *nocare1) /* if Xt - XtInputId *id; */
  738. {
  739. char *sessid;
  740. if (dtSvcProcIdG) {
  741. /*
  742. * NULL the global to indicate that we no longer want to
  743. * chit-chat with Tooltalk.
  744. */
  745. dtSvcProcIdG = (char *) NULL;
  746. sessid = tt_default_session();
  747. tt_session_quit(sessid);
  748. tt_free(sessid);
  749. tt_close();
  750. }
  751. /*
  752. * Unregister the Tooltalk fildes from the select mask.
  753. */
  754. if (ttfdG != -1) {
  755. BITCLEAR(allactivefdsG, ttfdG);
  756. ttfdG = -1;
  757. }
  758. }
  759. /******************************************************************************
  760. *
  761. * Alternate input handler to tttk_Xt_input_handler
  762. *
  763. * If we end up pulling Xt in, toss this routine and use
  764. * tttk_Xt_input_handler instead.
  765. *
  766. *****************************************************************************/
  767. void
  768. input_handler(
  769. char *nocare1, /* if Xt - XtPointer w */
  770. int *nocare2, /* if Xt - int *source */
  771. unsigned long *nocare3) /* if Xt - XtInputId *id; */
  772. {
  773. Tt_message msg;
  774. Tt_status status;
  775. msg = tt_message_receive();
  776. status = tt_ptr_error( msg );
  777. if (status != TT_OK) {
  778. /*
  779. * Problem; think about bailing.
  780. */
  781. if (status == TT_ERR_NOMP) {
  782. /*
  783. * Big time lost.
  784. */
  785. DetachFromTooltalk(NULL);
  786. }
  787. return;
  788. }
  789. if (msg == 0) {
  790. /*
  791. * A pattern callback ate the message for us.
  792. */
  793. return;
  794. }
  795. /*
  796. * All messages should have been consumed by a callback.
  797. * Pick between failing and rejecting the msg.
  798. */
  799. status = dtexec_tttk_message_abandon( msg );
  800. if (status != TT_OK) {
  801. /* don't care */
  802. }
  803. }
  804. /******************************************************************************
  805. *
  806. * Initiallize Tooltalk world.
  807. *
  808. *****************************************************************************/
  809. static void
  810. ToolTalkError(char *errfmt, Tt_status status)
  811. {
  812. char *statmsg;
  813. if (! tt_is_err(status)) return;
  814. statmsg = tt_status_message(status);
  815. DtMsgLogMessage( "Dtexec", DtMsgLogStderr, errfmt, statmsg );
  816. }
  817. int InitializeTooltalk(void)
  818. {
  819. char * procid;
  820. Tt_status status;
  821. int fd;
  822. procid = tt_default_procid();
  823. status = tt_ptr_error(procid);
  824. if ((status == TT_ERR_NOMP) || (status == TT_ERR_PROCID)) {
  825. /*
  826. * We need to try to establish a connection
  827. */
  828. procid = tt_open();
  829. status = tt_ptr_error(procid);
  830. if (status != TT_OK) {
  831. ToolTalkError("Could not connect to ToolTalk:\n%s\n", status);
  832. return (False);
  833. }
  834. tt_free(procid);
  835. /*
  836. * Determine the Tooltalk fildes.
  837. */
  838. fd = tt_fd();
  839. status = tt_int_error(fd);
  840. if (status != TT_OK) {
  841. ToolTalkError("Could not connect to ToolTalk:\n%s\n", status);
  842. tt_close();
  843. ttfdG = -1;
  844. return(False);
  845. }
  846. else {
  847. ttfdG = fd;
  848. }
  849. #ifdef DtActUseXtOverSelect
  850. /*
  851. * Add the ToolTalk file descriptor to the set monitored by Xt
  852. */
  853. XtAddInput(fd, (XtPointer)XtInputReadMask, input_handler, 0);
  854. #endif /* DtActUseXtOverSelect */
  855. }
  856. return (True);
  857. }
  858. /******************************************************************************
  859. *
  860. * Send some identification back to libDtSvc so it can talk back to
  861. * dtexec. The request format is:
  862. *
  863. * op(_DtActDtexecID) - the pattern
  864. * iarg(invID) - matches libDtSvc's invocation ID
  865. * iarg(childID) - matches libDtSvc's child ID
  866. * arg(dtexec's ProcID) - dtexec's procid handle
  867. *
  868. * libDtSvc should be able to pluck the invID and childID to immediately
  869. * dereference into it's Child-Invocation-Record that is tracking this
  870. * dtexec invocation. It just slips in "dtexec's ProcID" and then full
  871. * two-way communication is established.
  872. *
  873. *****************************************************************************/
  874. /*************************************************
  875. *
  876. * Routine to catch identification reply.
  877. */
  878. Tt_callback_action IdSelfToCallerReplyCB(
  879. Tt_message msg,
  880. Tt_pattern pattern)
  881. {
  882. Tt_state state;
  883. Tt_status status;
  884. char *errorMsg;
  885. status = tt_message_status(msg);
  886. state = tt_message_state(msg);
  887. if (state == TT_FAILED) {
  888. /*
  889. * tjg: At some point, may want to dump the following error
  890. * message into a log file. May have to wrap long messages.
  891. */
  892. if (status < TT_ERR_LAST)
  893. errorMsg = tt_status_message(status);
  894. else
  895. errorMsg = tt_message_status_string(msg);
  896. dtexec_tttk_message_destroy(msg);
  897. DetachFromTooltalk(NULL);
  898. }
  899. else if (state == TT_HANDLED) {
  900. dtexec_tttk_message_destroy(msg);
  901. /*
  902. * Nothing substantial to do with the request-reply in the current
  903. * implementation.
  904. */
  905. }
  906. else {
  907. }
  908. return( (Tt_callback_action) TT_CALLBACK_PROCESSED );
  909. }
  910. /*************************************************
  911. *
  912. * Routine to send identification request.
  913. */
  914. void IdSelfToCallerRequest(void)
  915. {
  916. Tt_message msg;
  917. Tt_status status;
  918. char *procid;
  919. procid = tt_default_procid();
  920. msg = dtexec_tttk_message_create( (Tt_message) NULL, TT_REQUEST, TT_SESSION,
  921. dtSvcProcIdG,
  922. "_DtActDtexecID",
  923. IdSelfToCallerReplyCB );
  924. tt_message_iarg_add( msg, TT_IN, dtexec_Tttk_integer, dtSvcInvIdG );
  925. tt_message_iarg_add( msg, TT_IN, dtexec_Tttk_integer, dtSvcChildIdG );
  926. tt_message_arg_add( msg, TT_IN, dtexec_Tttk_message_id, procid );
  927. status = tt_message_send( msg );
  928. tt_free(procid);
  929. if (status != TT_OK) {
  930. dtexec_tttk_message_destroy( msg );
  931. DetachFromTooltalk(NULL);
  932. }
  933. }
  934. /******************************************************************************
  935. *
  936. * Send a Done notice back to libDtSvc.
  937. *
  938. * _DtActDtexecDone
  939. * iarg(invID) - matches libDtSvc's invocation ID
  940. * iarg(childID) - matches libDtSvc's child ID
  941. * iarg(DtActionStatus) - a DtActionStatus style code
  942. *
  943. *****************************************************************************/
  944. /*************************************************
  945. *
  946. * Routine to catch identification reply.
  947. */
  948. Tt_callback_action DoneRequestReplyCB(
  949. Tt_message msg,
  950. Tt_pattern pattern)
  951. {
  952. Tt_state state;
  953. Tt_status replyStatus;
  954. state = tt_message_state(msg);
  955. if (state == TT_FAILED) {
  956. dtexec_tttk_message_destroy(msg);
  957. DetachFromTooltalk(NULL);
  958. shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
  959. }
  960. else if (state == TT_HANDLED) {
  961. dtexec_tttk_message_destroy(msg);
  962. shutdownPhaseG = SDP_DONE_REPLIED;
  963. }
  964. else {
  965. }
  966. return( (Tt_callback_action) TT_CALLBACK_PROCESSED );
  967. }
  968. /*************************************************
  969. *
  970. * Routine to send done request.
  971. */
  972. void DoneRequest(int doneCode)
  973. {
  974. static int beenhere = 0;
  975. Tt_message msg;
  976. Tt_status status;
  977. char *procid;
  978. /*
  979. * Only allow one Done(Request) to be issued.
  980. */
  981. if (!beenhere) {
  982. beenhere = 1;
  983. procid = tt_default_procid();
  984. msg = dtexec_tttk_message_create( (Tt_message) NULL,
  985. TT_REQUEST, TT_SESSION,
  986. dtSvcProcIdG,
  987. "_DtActDtexecDone",
  988. DoneRequestReplyCB );
  989. tt_message_iarg_add( msg, TT_IN, dtexec_Tttk_integer, dtSvcInvIdG );
  990. tt_message_iarg_add( msg, TT_IN, dtexec_Tttk_integer, dtSvcChildIdG );
  991. tt_message_iarg_add( msg, TT_IN, dtexec_Tttk_integer, doneCode );
  992. status = tt_message_send( msg );
  993. tt_free(procid);
  994. if (status != TT_OK) {
  995. dtexec_tttk_message_destroy( msg );
  996. DetachFromTooltalk(NULL);
  997. }
  998. }
  999. }
  1000. /******************************************************************************
  1001. *
  1002. * main
  1003. *
  1004. *****************************************************************************/
  1005. int
  1006. main (
  1007. int argc,
  1008. char **argv )
  1009. {
  1010. char **cmdLine;
  1011. int success;
  1012. fd_set readfds, exceptfds;
  1013. int nfound;
  1014. struct timeval timeoutShort, timeoutLong;
  1015. int junki,i;
  1016. char *tmpBuffer;
  1017. int errorBytes;
  1018. struct stat statBuffer;
  1019. int firstPass, tmpi;
  1020. char *tmpProgName = NULL;
  1021. setlocale( LC_ALL, "" );
  1022. #ifdef _DTEXEC_NLS16
  1023. Dt_nlInit();
  1024. #endif /* _DTEXEC_NLS16 */
  1025. /*
  1026. * For debugging purposes, a way to pause the process and allow
  1027. * time for a xdb -P debugger attach. If no args, (e.g. libDtSvc is
  1028. * test running the executable), cruise on.
  1029. */
  1030. if (getenv("_DTEXEC_DEBUG") && (argc > 1)) {
  1031. /*
  1032. * Don't block in a system call, or on libDtSvc's attempts to
  1033. * just test exec us.
  1034. */
  1035. SPINBLOCK
  1036. }
  1037. /*
  1038. * Note: dtSvcProcIdG is used like a boolean to control whether
  1039. * we are communicating with libDtSvc using Tooltalk.
  1040. */
  1041. dtSvcProcIdG = (char *) NULL; /* assume not communicating with TT */
  1042. ttfdG = -1;
  1043. cmdLine = ParseCommandLine (argc, argv);
  1044. /*
  1045. * If a signal goes off *outside* the upcoming select, we'll need to
  1046. * rediscover the signal by letting select() timeout.
  1047. *
  1048. * We might also set a rediscover flag to fake a signal response.
  1049. */
  1050. rediscoverSigCldG = 0; /* boolean and counter */
  1051. rediscoverUrgentSigG = 0; /* boolean and counter */
  1052. InitializeSignalHandling ();
  1053. /*
  1054. * Create a pipe for logging of errors for actions without
  1055. * windows.
  1056. */
  1057. errorpipeG[0] = -1; /* by default, no stderr redirection */
  1058. errorpipeG[1] = -1;
  1059. if ( requestTypeG == TRANSIENT ) { /* should be WINDOW_TYPE NO_STDIO */
  1060. if ( pipe(errorpipeG) == -1 ) {
  1061. errorpipeG[0] = -1;
  1062. errorpipeG[1] = -1;
  1063. }
  1064. }
  1065. if (cmdLine) {
  1066. success = ExecuteCommand (cmdLine);
  1067. if (!success) {
  1068. /*
  1069. * Act like we were killed - it will result in a
  1070. * DtACTION_FAILED.
  1071. */
  1072. childPidG = -1;
  1073. rediscoverUrgentSigG = 1;
  1074. }
  1075. }
  1076. else {
  1077. /*
  1078. * Act like we had a child and it went away - it will result
  1079. * in a DtACTION_DONE.
  1080. */
  1081. childPidG = -1;
  1082. rediscoverSigCldG = 1;
  1083. }
  1084. /*
  1085. * Note when we started so we can compare times when we finish.
  1086. */
  1087. (void) gettimeofday (&startTimeG, &zoneG);
  1088. if (dtSvcProcIdG) {
  1089. if ( !InitializeTooltalk() ) {
  1090. /*
  1091. * We have no hope of talking to our caller via Tooltalk.
  1092. */
  1093. dtSvcProcIdG = (char *) NULL;
  1094. }
  1095. }
  1096. /*
  1097. * Tie in to the default session and start chatting.
  1098. */
  1099. if (dtSvcProcIdG) tt_session_join(tt_default_session());
  1100. /*
  1101. * Finally send caller our current proc id so they can talk back.
  1102. */
  1103. if (dtSvcProcIdG) IdSelfToCallerRequest();
  1104. /*
  1105. * Monitor file descriptors for activity. If errors occur on a fds,
  1106. * it will be removed from allactivefdsG after handling the error.
  1107. */
  1108. CLEARBITS(allactivefdsG);
  1109. /*
  1110. * Add Tooltalk
  1111. */
  1112. if ( ttfdG != -1 )
  1113. BITSET(allactivefdsG, ttfdG); /* add Tooltalk */
  1114. /*
  1115. * Add Error Log
  1116. */
  1117. if ( errorpipeG[0] != -1 )
  1118. BITSET(allactivefdsG, errorpipeG[0]); /* add read side of error pipe */
  1119. /*
  1120. * Set options for rediscovery and not-rediscovery modes of
  1121. * operation.
  1122. */
  1123. shutdownPhaseG = SDP_DONE_STARTING; /* triggered with rediscoverSigCldG */
  1124. timeoutShort.tv_sec = 0; /* in quick rediscovery mode */
  1125. timeoutShort.tv_usec = SHORT_SELECT_TIMEOUT;
  1126. timeoutLong.tv_sec = 86400; /* don't thrash on rediscovery */
  1127. timeoutLong.tv_usec = 0;
  1128. for (;;) {
  1129. COPYBITS(allactivefdsG, readfds);
  1130. COPYBITS(allactivefdsG, exceptfds);
  1131. if (rediscoverSigCldG || rediscoverUrgentSigG) {
  1132. nfound =select(MAXSOCKS, FD_SET_CAST(&readfds), FD_SET_CAST(NULL),
  1133. FD_SET_CAST(&exceptfds), &timeoutShort);
  1134. }
  1135. else {
  1136. nfound =select(MAXSOCKS, FD_SET_CAST(&readfds), FD_SET_CAST(NULL),
  1137. FD_SET_CAST(&exceptfds), &timeoutLong);
  1138. }
  1139. if (nfound == -1) {
  1140. /*
  1141. * Handle select() problem.
  1142. */
  1143. if (errno == EINTR) {
  1144. /*
  1145. * A signal happened - let rediscover flags redirect flow
  1146. * via short select timeouts.
  1147. */
  1148. }
  1149. else if ((errno == EBADF) || (errno == EFAULT)) {
  1150. /*
  1151. * A connection probably dropped.
  1152. */
  1153. if (ttfdG != -1) {
  1154. if ( GETBIT(exceptfds, ttfdG) ) {
  1155. /*
  1156. * Tooltalk connection has gone bad.
  1157. *
  1158. * Judgement call - when the Tooltalk connection goes
  1159. * bad, let dtexec continue rather than doing an exit.
  1160. */
  1161. DetachFromTooltalk(NULL);
  1162. }
  1163. }
  1164. if (errorpipeG[0] != -1) {
  1165. if ( GETBIT(exceptfds, errorpipeG[0]) ) {
  1166. /*
  1167. * Error pipe has gone bad.
  1168. */
  1169. close(errorpipeG[0]);
  1170. BITCLEAR(allactivefdsG, errorpipeG[0]);
  1171. errorpipeG[0] = -1;
  1172. }
  1173. }
  1174. }
  1175. else {
  1176. /*
  1177. * We have bad paremeters to select()
  1178. */
  1179. }
  1180. /*
  1181. * So that select() errors cannot dominate, now behave as
  1182. * though only a timeout had occured.
  1183. */
  1184. nfound = 0;
  1185. }
  1186. if (nfound > 0) {
  1187. /*
  1188. * Have some input to process. Figure out who.
  1189. */
  1190. if (ttfdG != -1) {
  1191. if ( GETBIT(readfds, ttfdG) ) {
  1192. /* Clear bit first, since calling input_handler() could */
  1193. /* have the side-effect of setting ttfdG to -1! */
  1194. BITCLEAR(readfds, ttfdG);
  1195. /*
  1196. * Tooltalk activity.
  1197. *
  1198. * Note that the input_handler parameters match
  1199. * an XtInputHandler() style callback in case Xt is
  1200. * ever used.
  1201. */
  1202. input_handler((char *) NULL, (int *) &junki,
  1203. (unsigned long *) &junki);
  1204. }
  1205. }
  1206. if (errorpipeG[0] != -1) {
  1207. if ( GETBIT(readfds, errorpipeG[0]) ) {
  1208. /*
  1209. * Stderr activity.
  1210. *
  1211. * Read the errorpipe until no more seems available.
  1212. * Call that good enough and write a time-stamped
  1213. * block to the errorLog file.
  1214. */
  1215. errorBytes = 0; /* what we have so far */
  1216. tmpBuffer = NULL;
  1217. firstPass = 1;
  1218. while (1) {
  1219. if ( fstat(errorpipeG[0], &statBuffer) ) {
  1220. break;
  1221. }
  1222. else if ( statBuffer.st_size > 0 ) {
  1223. /*
  1224. * Grow buffer to hold entire error stream.
  1225. */
  1226. firstPass = 0;
  1227. if (tmpBuffer == NULL)
  1228. tmpBuffer = (char *) malloc(
  1229. statBuffer.st_size + 1);
  1230. else
  1231. tmpBuffer = (char *) realloc( tmpBuffer,
  1232. errorBytes +
  1233. statBuffer.st_size + 1);
  1234. /*
  1235. * Drain error pipe.
  1236. */
  1237. tmpi = read (errorpipeG[0], &tmpBuffer[errorBytes],
  1238. statBuffer.st_size);
  1239. if (tmpi > 0) /* else let fstat() redetect problem */
  1240. errorBytes += tmpi;
  1241. tmpBuffer[errorBytes] = '\0';
  1242. if (errorBytes < 65535) {
  1243. /*
  1244. * Pause a bit and wait for a continuation of
  1245. * the error stream if there is more.
  1246. */
  1247. select(0, FD_SET_CAST(NULL),
  1248. FD_SET_CAST(NULL),
  1249. FD_SET_CAST(NULL), &timeoutShort);
  1250. }
  1251. else {
  1252. /*
  1253. * We have enough to do a dump now.
  1254. */
  1255. break;
  1256. }
  1257. }
  1258. else {
  1259. /*
  1260. * No more to read.
  1261. */
  1262. if (firstPass) {
  1263. /*
  1264. * On the first pass after select(), if we have 0 bytes,
  1265. * it really means the pipe has gone down.
  1266. */
  1267. close(errorpipeG[0]);
  1268. BITCLEAR(allactivefdsG, errorpipeG[0]);
  1269. BITCLEAR(readfds, errorpipeG[0]);
  1270. errorpipeG[0] = -1;
  1271. }
  1272. break;
  1273. }
  1274. }
  1275. if (tmpBuffer) {
  1276. if (!tmpProgName) {
  1277. tmpProgName = (char *) malloc (strlen (argv[0]) +
  1278. strlen (cmdLine[0]) +
  1279. 5);
  1280. if (!tmpProgName)
  1281. tmpProgName = argv[0];
  1282. else {
  1283. /*
  1284. * To identify the process for this stderr,
  1285. * use both argv[0] and the name of the
  1286. * process that was execvp'd
  1287. */
  1288. (void) strcpy (tmpProgName, "(");
  1289. (void) strcat (tmpProgName, argv[0]);
  1290. (void) strcat (tmpProgName, ") ");
  1291. (void) strcat (tmpProgName, cmdLine[0]);
  1292. }
  1293. }
  1294. DtMsgLogMessage( tmpProgName, DtMsgLogStderr, "%s",
  1295. tmpBuffer );
  1296. free( tmpBuffer );
  1297. }
  1298. if (errorpipeG[0] != -1)
  1299. BITCLEAR(readfds, errorpipeG[0]);
  1300. }
  1301. }
  1302. /*
  1303. * So that select() data cannot dominate, now behave as
  1304. * though only a timeout had occured.
  1305. */
  1306. nfound = 0;
  1307. }
  1308. if (nfound == 0) {
  1309. /*
  1310. * Timeout. We are probably rediscovering and have entered
  1311. * a shutdown phase. The following rediscover handlers are
  1312. * in priority order.
  1313. *
  1314. * Note that by way of timeouts and events, we will make
  1315. * multiple passes through this block of code.
  1316. */
  1317. if (rediscoverUrgentSigG) {
  1318. /*
  1319. * Handle urgent signal.
  1320. *
  1321. * Tact: wait awhile and see if a SIGCLD will happen.
  1322. * If it does, then a normal shutdown will suffice.
  1323. * If a SIGCLD does not happen, then do a raw exit(0).
  1324. * Exit is required for BBA anyway.
  1325. */
  1326. if (rediscoverSigCldG)
  1327. /*
  1328. * Rather than act on the Urgent Signal, defer to the
  1329. * SIGCLD Signal shutdown process.
  1330. */
  1331. rediscoverUrgentSigG = 0;
  1332. else
  1333. /*
  1334. * Still in a mode where we have an outstanding
  1335. * Urgent Signal but no SIGCLD. Bump a counter
  1336. * which moves us closer to doing an exit().
  1337. */
  1338. rediscoverUrgentSigG++;
  1339. /*
  1340. * After 5 seconds (add select timeout too) waiting for
  1341. * a SIGCLD, give up and exit.
  1342. */
  1343. if (rediscoverUrgentSigG > ((1000/SHORT_SELECT_TIMEOUT)*5) ) {
  1344. #if defined(__aix) || defined (__osf__)
  1345. PanicSignal(0);
  1346. #else
  1347. PanicSignal();
  1348. #endif
  1349. }
  1350. }
  1351. if (rediscoverSigCldG) {
  1352. /*
  1353. * Handle SIGCLD signal.
  1354. *
  1355. * Under SIGCLD, we will make multiple passes through the
  1356. * following, implementing a phased shutdown.
  1357. */
  1358. if (shutdownPhaseG == SDP_DONE_STARTING) {
  1359. /*
  1360. * Send Done(Request) for starters.
  1361. */
  1362. if (dtSvcProcIdG) DoneRequest(_DtActCHILD_DONE);
  1363. if (dtSvcProcIdG) {
  1364. /*
  1365. * Sit and wait for the Done Reply in select()
  1366. */
  1367. shutdownPhaseG = SDP_DONE_REPLY_WAIT;
  1368. }
  1369. else {
  1370. /*
  1371. * Unable to send Done Reply. Assume we're on
  1372. * our own from now on.
  1373. */
  1374. shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
  1375. }
  1376. }
  1377. if (shutdownPhaseG == SDP_DONE_REPLY_WAIT) {
  1378. /*
  1379. * After 5 minutes of passing through REPLY_WAIT,
  1380. * assume the Done(Reply) will never come in and
  1381. * move on.
  1382. */
  1383. rediscoverSigCldG++;
  1384. if (rediscoverSigCldG > ((1000/SHORT_SELECT_TIMEOUT)*300)) {
  1385. if (dtSvcProcIdG) {
  1386. /*
  1387. * Try to detatch from Tooltalk anyway.
  1388. */
  1389. DetachFromTooltalk(NULL);
  1390. }
  1391. shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
  1392. }
  1393. /*
  1394. * See if the Tooltalk connection is still alive. If
  1395. * not, then no reason to wait around.
  1396. */
  1397. else if (!dtSvcProcIdG) {
  1398. shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
  1399. }
  1400. }
  1401. if (shutdownPhaseG == SDP_DONE_REPLIED) {
  1402. /*
  1403. * We have our Done(Reply), so proceed.
  1404. */
  1405. if (dtSvcProcIdG)
  1406. shutdownPhaseG = SDP_FINAL_LINGER;
  1407. else
  1408. shutdownPhaseG = SDP_DONE_PANIC_CLEANUP;
  1409. }
  1410. if (shutdownPhaseG == SDP_DONE_PANIC_CLEANUP) {
  1411. /*
  1412. * We cannot talk with caller, so do cleanup
  1413. * of tmp files.
  1414. */
  1415. for (i = 0; i < tmpFileCntG; i++ ) {
  1416. chmod( tmpFilesG[i], (S_IRUSR|S_IWUSR) );
  1417. unlink( tmpFilesG[i] );
  1418. }
  1419. shutdownPhaseG = SDP_FINAL_LINGER;
  1420. }
  1421. if (shutdownPhaseG == SDP_FINAL_LINGER) {
  1422. /*
  1423. * All done.
  1424. */
  1425. static int skipFirst = 1;
  1426. if (skipFirst) {
  1427. /*
  1428. * Rather than a quick departure from the select()
  1429. * loop, make one more pass. If the child has gone
  1430. * down quickly, the SIGCLD may have caused us to
  1431. * get here before any errorPipeG information has
  1432. * had a chance to reach us.
  1433. */
  1434. skipFirst = 0;
  1435. }
  1436. else {
  1437. FinalLinger();
  1438. }
  1439. }
  1440. }
  1441. }
  1442. }
  1443. }