home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / com / utils / elm / sources / syscall.c < prev    next >
C/C++ Source or Header  |  1992-05-03  |  12KB  |  445 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: syscall.c,v 4.1.1.4 90/07/12 22:41:55 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1.1.4 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    syscall.c,v $
  17.  * Revision 4.1.1.4  90/07/12  22:41:55  syd
  18.  * Make it aware of the fact that we loose the cursor position on
  19.  * some system calls, so set it far enough off an absolute move will
  20.  * be done on the next cursor address, and then place it where we want it.
  21.  * From: Syd, reported by Douglas Lamb
  22.  *
  23.  * Revision 4.1.1.3  90/06/21  22:48:17  syd
  24.  * patch to fix up the Log headers.
  25.  * From: pdc%lunch.wpd@sgi.com (Paul Close)
  26.  *
  27.  * Revision 4.1.1.2  90/06/09  22:00:13  syd
  28.  * Use a close-on-exec pipe to diagnose exec() failures.
  29.  * From: tct!chip@uunet.UU.NET (Chip Salzenberg)
  30.  *
  31.  * Revision 4.1.1.1  90/06/09  21:33:22  syd
  32.  * Some wait(2) system calls return -1 and set errno=EINTR (interrupted system
  33.  * call) when the editor is invoked, suspended, and then resumed.  Loop until
  34.  * wait either returns pid, or returns -1 with errno != EINTR.
  35.  * From: pdc%lunch.wpd@sgi.com (Paul Close)
  36.  *
  37.  * Revision 4.1  90/04/28  22:44:18  syd
  38.  * checkin of Elm 2.3 as of Release PL0
  39.  *
  40.  *
  41.  ******************************************************************************/
  42.  
  43. /** These routines are used for user-level system calls, including the
  44.     '!' command and the '|' commands...
  45.  
  46. **/
  47.  
  48. #include "headers.h"
  49.  
  50. #include <signal.h>
  51. #include <errno.h>
  52.  
  53. #ifdef BSD
  54. #  include <sys/wait.h>
  55. #endif
  56.  
  57. #ifdef OS2
  58. #  include <process.h>
  59. #endif
  60.  
  61. char *argv_zero();
  62. void  _exit();
  63.  
  64. #ifdef ALLOW_SUBSHELL
  65.  
  66. int
  67. subshell()
  68. {
  69.     /** spawn a subshell with either the specified command
  70.         returns non-zero if screen rewrite needed
  71.     **/
  72.  
  73.     char command[SLEN];
  74.     int  old_raw, helpful, ret;
  75.  
  76.     helpful = (user_level == 0);
  77.  
  78.     if (helpful)
  79. #ifdef OS2
  80.       PutLine0(LINES-3,COLUMNS-40,"(Enter empty command for a shell.)");
  81. #else
  82.       PutLine0(LINES-3,COLUMNS-40,"(Use the shell name for a shell.)");
  83. #endif
  84.     PutLine0(LINES-2,0,"Shell command: ");
  85.     CleartoEOS();
  86.     command[0] = '\0';
  87.     (void) optionally_enter(command, LINES-2, 15, FALSE, FALSE);
  88. #ifndef OS2
  89.     if (command[0] == 0) {
  90.       if (helpful)
  91.         MoveCursor(LINES-3,COLUMNS-40);
  92.       else
  93.         MoveCursor(LINES-2,0);
  94.       CleartoEOS();
  95.       return 0;
  96.     }
  97. #endif
  98.  
  99.     MoveCursor(LINES,0);
  100.     CleartoEOLN();
  101.  
  102.     if ((old_raw = RawState()) == ON)
  103.       Raw(OFF);
  104.     softkeys_off();
  105.     if (cursor_control)
  106.       transmit_functions(OFF);
  107.  
  108.     umask(original_umask);    /* restore original umask so users new files are ok */
  109.     ret = system_call(command, USER_SHELL, TRUE, TRUE);
  110.     umask(077);        /* now put it back to private for mail files */
  111.  
  112.     SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  113.     Raw(ON);
  114.     if (command[0]) {
  115.         PutLine0(LINES, 0, "\r\n\r\nPress any key to return to ELM: ");
  116.         (void) getchar();
  117.     }
  118.     if (old_raw == OFF)
  119.       Raw(OFF);
  120.     softkeys_on();
  121.     if (cursor_control)
  122.       transmit_functions(ON);
  123.  
  124.     if (ret && command[0])
  125.       error1("Return code was %d.", ret);
  126.  
  127.     return 1;
  128. }
  129.  
  130. #endif /* ALLOW_SUBSHELL */
  131.  
  132. system_call(string, shell_type, allow_signals, allow_interrupt)
  133. char *string;
  134. int   shell_type, allow_signals, allow_interrupt;
  135. {
  136.     /** execute 'string', setting uid to userid... **/
  137.     /** if shell-type is "SH" /bin/sh is used regardless of the
  138.         users shell setting.  Otherwise, "USER_SHELL" is sent.
  139.         If allow_signals is TRUE, then allow the executed
  140.         command handle hangup, and optionally if allow_interrupt
  141.         is also true handle interrupt in its own way.
  142.         This is useful for executed programs with
  143.         user interaction that handle those signals on their
  144.         own terms. It is especially important for vi, so that
  145.         a message being edited when a user connection is
  146.         dropped is recovered by vi's expreserve program **/
  147.  
  148.     int pfd[2], stat, pid, w, iteration;
  149.     char *sh;
  150. #if defined(BSD) && !defined(WEXITSTATUS)
  151.     union wait status;
  152. #else
  153.     int status;
  154. #endif
  155. #ifdef VOIDSIG
  156.     register void (*istat)(), (*qstat)();
  157. # ifdef SIGTSTP
  158.     register void (*oldstop)(), (*oldstart)();
  159. # endif
  160. #else
  161.     register int (*istat)(), (*qstat)();
  162. # ifdef SIGTSTP
  163.     register int (*oldstop)(), (*oldstart)();
  164. # endif
  165. #endif
  166. #ifndef OS2
  167.     extern int errno;
  168. #endif
  169.  
  170.     sh = (shell_type == USER_SHELL) ? shell : "/bin/sh";
  171.     dprint(2, (debugfile, "System Call: %s\n\t%s\n", sh, string));
  172.  
  173. #ifdef OS2
  174.         tflush();
  175.  
  176.     if ( shell_type != USER_SHELL )
  177.           if ( (sh = getenv("COMSPEC")) == NULL )
  178.             if ( (sh = getenv("SHELL")) == NULL )
  179.               sh = default_shell;
  180.  
  181.         stat = spawnlp(P_WAIT, sh, sh, string[0] ? "/c" : NULL, string, NULL);
  182. #else
  183.     /*
  184.      * Note the neat trick with close-on-exec pipes.
  185.      * If the child's exec() succeeds, then the pipe read returns zero.
  186.      * Otherwise, it returns the zero byte written by the child
  187.      * after the exec() is attempted.  This is the cleanest way I know
  188.      * to discover whether an exec() failed.   --CHS
  189.      */
  190.  
  191.     if (pipe(pfd) == -1) {
  192.       perror("pipe");
  193.       return -1;
  194.     }
  195.     fcntl(pfd[0], F_SETFD, 1);
  196.     fcntl(pfd[1], F_SETFD, 1);
  197.  
  198.     istat = signal(SIGINT, SIG_IGN);
  199.     qstat = signal(SIGQUIT, SIG_IGN);
  200. #ifdef SIGTSTP
  201.     oldstop = signal(SIGTSTP, SIG_DFL);
  202.     oldstart = signal(SIGCONT, SIG_DFL);
  203. #endif
  204.  
  205.     stat = -1;        /* Assume failure. */
  206.  
  207.     for (iteration = 0; iteration < 5; ++iteration) {
  208.       if (iteration > 0)
  209.         sleep(2);
  210.  
  211. #ifdef VFORK
  212.       pid = vfork();
  213. #else
  214.       pid = fork();
  215. #endif
  216.  
  217.       if (pid != -1)
  218.         break;
  219.     }
  220.  
  221.     if (pid == -1) {
  222.       perror("fork");
  223.     }
  224.     else if (pid == 0) {
  225.       /*
  226.        * Set group and user back to their original values.
  227.        * Note that group must be set first.
  228.        */
  229.       setgid(groupid);
  230.       setuid(userid);
  231.  
  232.       /*
  233.        * Program to exec may or may not be able to handle
  234.        * interrupt, quit, hangup and stop signals.
  235.        */
  236.       (void) signal(SIGHUP, allow_signals ? SIG_DFL : SIG_IGN);
  237.       (void) signal(SIGINT, (allow_signals && allow_interrupt)?SIG_DFL:SIG_IGN);
  238.       (void) signal(SIGQUIT, (allow_signals && allow_interrupt)?SIG_DFL:SIG_IGN);
  239. #ifdef SIGTSTP
  240.       (void) signal(SIGTSTP, allow_signals ? SIG_DFL : SIG_IGN);
  241.       (void) signal(SIGCONT, allow_signals ? SIG_DFL : SIG_IGN);
  242. #endif
  243.  
  244.       /* Go for it. */
  245.       execl(sh, argv_zero(sh), "-c", string, (char *) 0);
  246.  
  247.       /* If exec fails, we write a byte to the pipe before exiting. */
  248.       perror(sh);
  249.       write(pfd[1], "", 1);
  250.       _exit(127);
  251.     }
  252.     else {
  253.       int rd;
  254.       char ch;
  255.  
  256.       /* Try to read a byte from the pipe. */
  257.       close(pfd[1]);
  258.       rd = read(pfd[0], &ch, 1);
  259.       close(pfd[0]);
  260.  
  261.       while ((w = wait(&status)) != pid)
  262.           if (w == -1 && errno != EINTR)
  263.           break;
  264.  
  265.       /* If we read a byte from the pipe, the exec failed. */
  266.       if (rd > 0)
  267.         stat = -1;
  268.       else if (w == pid) {
  269. #ifdef    WEXITSTATUS
  270.         stat = WEXITSTATUS(status);
  271. #else
  272. # ifdef    BSD
  273.         stat = status.w_retcode;
  274. # else
  275.         stat = status;
  276. # endif
  277. #endif
  278.       }
  279.       }
  280.  
  281.     (void) signal(SIGINT, istat);
  282.     (void) signal(SIGQUIT, qstat);
  283. #ifdef SIGTSTP
  284.     (void) signal(SIGTSTP, oldstop);
  285.     (void) signal(SIGCONT, oldstart);
  286. #endif
  287.  
  288. #endif  /* OS2 */
  289.  
  290.     return(stat);
  291. }
  292.  
  293. int
  294. do_pipe()
  295. {
  296.     /** pipe the current message or tagged messages to
  297.         the specified sequence.. **/
  298.  
  299.     char command[SLEN], buffer[SLEN], message_list[SLEN];
  300.     register int  ret, to_pipe;
  301.     int    old_raw;
  302.  
  303.     to_pipe = make_msg_list(message_list);
  304.     sprintf(buffer, "Pipe message%s to: ", plural(to_pipe));
  305.         PutLine0(LINES-2,0,buffer);
  306.  
  307.     command[0] = '\0';
  308.  
  309.     (void) optionally_enter(command, LINES-2, strlen(buffer), FALSE, FALSE);
  310.     if (strlen(command) == 0) {
  311.       MoveCursor(LINES-2,0);    CleartoEOLN();
  312.       return(0);
  313.     }
  314.  
  315.     MoveCursor(LINES,0);     CleartoEOLN();
  316.     if (( old_raw = RawState()) == ON)
  317.       Raw(OFF);
  318.  
  319.     if (cursor_control)  transmit_functions(OFF);
  320.  
  321.     sprintf(buffer, "%s -f %s -h %s | %s",
  322.         readmsg,
  323.         (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  324.         message_list,
  325.         command);
  326.  
  327.     ret = system_call(buffer, USER_SHELL, TRUE, TRUE);
  328.  
  329.     SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  330.     PutLine0(LINES, 0, "\n\nPress any key to return to ELM.");
  331.     if (old_raw == ON)
  332.        Raw(ON);
  333.     (void) getchar();
  334.     if (cursor_control)  transmit_functions(ON);
  335.  
  336.     if (ret != 0) error1("Return code was %d.", ret);
  337.     return(1);
  338. }
  339.  
  340. print_msg()
  341. {
  342.     /** Print current message or tagged messages using 'printout'
  343.         variable.  Error message iff printout not defined! **/
  344.  
  345.     char buffer[SLEN], filename[SLEN], printbuffer[SLEN];
  346.     char message_list[SLEN];
  347.     register int  retcode, to_print, cnt;
  348.  
  349.     if (strlen(printout) == 0) {
  350.       error("Don't know how to print - option \"printmail\" undefined!");
  351.       return;
  352.     }
  353.  
  354.     to_print = make_msg_list(message_list);
  355.  
  356.     sprintf(filename,"%s%d%s", temp_dir, getpid(), temp_print);
  357.     for ( cnt = 0; filename[cnt]; cnt++ )
  358.       if ( filename[cnt] == '/' )
  359.         filename[cnt] = '\\';
  360.     /* some OS/2 print programs :-) are very picky about forward slashes */
  361.  
  362.     if (in_string(printout, "%s"))
  363.       sprintf(printbuffer, printout, filename);
  364.     else
  365.       sprintf(printbuffer, "%s %s", printout, filename);
  366.  
  367.     sprintf(buffer,"%s -p -f %s %s >%s & %s 1>nul 2>nul",
  368.         readmsg,
  369.         (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  370.         message_list,
  371.         filename,
  372.         printbuffer);
  373.  
  374.     dprint(2, (debugfile, "Printing system call...\n"));
  375.  
  376.       Centerline(LINES, "Queuing...");
  377.  
  378.     if ((retcode = system_call(buffer, SH, FALSE, FALSE)) == 0) {
  379.       sprintf(buffer, "Message%s queued up to print.", plural(to_print));
  380.       Centerline(LINES, buffer);
  381.     }
  382.     else
  383.       error1("Printout failed with return code %d.", retcode);
  384.  
  385.     unlink(filename);    /* remove da temp file! */
  386. }
  387.  
  388. make_msg_list(message_list)
  389. char *message_list;
  390. {
  391.     /** make a list of the tagged or just the current, if none tagged.
  392.         check for overflow on messsage length
  393.          **/
  394.  
  395.     int i, msgs_selected = 0;
  396.  
  397.     *message_list = '\0';    /* start with an empty list */
  398.  
  399.     for (i=0; i < message_count; i++)
  400.       if (headers[i]->status & TAGGED) {
  401.         if (strlen(message_list) + 6 >= SLEN) {
  402.           error1("Too many messages selected, messages from %d on not used", i);
  403.           return(msgs_selected);
  404.           }
  405.         sprintf(message_list, "%s %d", message_list,
  406.             headers[i]->index_number);
  407.         msgs_selected++;
  408.       }
  409.  
  410.     if (! msgs_selected) {
  411.       sprintf(message_list," %d", headers[current-1]->index_number);
  412.       msgs_selected = 1;
  413.     }
  414.  
  415.     return(msgs_selected);
  416. }
  417.  
  418. list_folders(numlines, helpmsg)
  419. unsigned numlines;
  420. char *helpmsg;
  421. {
  422.     /** list the folders in the users FOLDERHOME directory.  This is
  423.         simply a call to "ls -C"
  424.         Numlines is the number of lines to scroll afterwards. This is
  425.         useful when a portion of the screen needs to be cleared for
  426.         subsequent prompts, but you don't want to overwrite the
  427.         list of folders.
  428.         Helpmsg is what should be printed before the listing if not NULL.
  429.     **/
  430.  
  431.     char buffer[SLEN];
  432.  
  433.     Raw(OFF);
  434.     ClearScreen();
  435.     MoveCursor(LINES, 0);
  436.     if(helpmsg)
  437.       printf(helpmsg);
  438.     sprintf(buffer, "dir /w \"%s\"", folders);
  439.     printf("\n\rContents of your folder directory:\n\r\n\r");
  440.     system_call(buffer, SH, FALSE, FALSE);
  441.     while(numlines--)
  442.         printf("\n\r");
  443.     Raw(ON);
  444. }
  445.