home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / ELM23-2 / ELM23-2.ZIP / src / syscall.c < prev    next >
C/C++ Source or Header  |  1996-01-17  |  12KB  |  468 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("OS2_SHELL")) == NULL )
  179.               sh = default_shell;
  180.  
  181.     if (string[0] == 0) /* interactive subshell */
  182.       stat = spawnlp(P_WAIT, sh, sh, NULL);
  183.     else
  184.     {
  185. #if 0
  186.       char cmd[VERY_LONG_STRING], *ptr;
  187.  
  188.       strcpy(cmd, string);
  189.       ptr = strchr(cmd, ' ');
  190.  
  191.       if (ptr == NULL)
  192.         stat = spawnlp(P_WAIT, sh, sh, "/c", string, NULL);
  193.       else
  194.       {
  195.         *ptr++ = 0;
  196.  
  197.         if ((stat = spawnlp(P_WAIT, cmd, cmd, ptr, NULL)) == -1)
  198.           stat = spawnlp(P_WAIT, sh, sh, "/c", string, NULL);
  199.       }
  200. #else
  201.       stat = spawnlp(P_WAIT, sh, sh, "/c", string, NULL);
  202. #endif
  203.     }
  204. #else
  205.     /*
  206.      * Note the neat trick with close-on-exec pipes.
  207.      * If the child's exec() succeeds, then the pipe read returns zero.
  208.      * Otherwise, it returns the zero byte written by the child
  209.      * after the exec() is attempted.  This is the cleanest way I know
  210.      * to discover whether an exec() failed.   --CHS
  211.      */
  212.  
  213.     if (pipe(pfd) == -1) {
  214.       perror("pipe");
  215.       return -1;
  216.     }
  217.     fcntl(pfd[0], F_SETFD, 1);
  218.     fcntl(pfd[1], F_SETFD, 1);
  219.  
  220.     istat = signal(SIGINT, SIG_IGN);
  221.     qstat = signal(SIGQUIT, SIG_IGN);
  222. #ifdef SIGTSTP
  223.     oldstop = signal(SIGTSTP, SIG_DFL);
  224.     oldstart = signal(SIGCONT, SIG_DFL);
  225. #endif
  226.  
  227.     stat = -1;        /* Assume failure. */
  228.  
  229.     for (iteration = 0; iteration < 5; ++iteration) {
  230.       if (iteration > 0)
  231.         sleep(2);
  232.  
  233. #ifdef VFORK
  234.       pid = vfork();
  235. #else
  236.       pid = fork();
  237. #endif
  238.  
  239.       if (pid != -1)
  240.         break;
  241.     }
  242.  
  243.     if (pid == -1) {
  244.       perror("fork");
  245.     }
  246.     else if (pid == 0) {
  247.       /*
  248.        * Set group and user back to their original values.
  249.        * Note that group must be set first.
  250.        */
  251.       setgid(groupid);
  252.       setuid(userid);
  253.  
  254.       /*
  255.        * Program to exec may or may not be able to handle
  256.        * interrupt, quit, hangup and stop signals.
  257.        */
  258.       (void) signal(SIGHUP, allow_signals ? SIG_DFL : SIG_IGN);
  259.       (void) signal(SIGINT, (allow_signals && allow_interrupt)?SIG_DFL:SIG_IGN);
  260.       (void) signal(SIGQUIT, (allow_signals && allow_interrupt)?SIG_DFL:SIG_IGN);
  261. #ifdef SIGTSTP
  262.       (void) signal(SIGTSTP, allow_signals ? SIG_DFL : SIG_IGN);
  263.       (void) signal(SIGCONT, allow_signals ? SIG_DFL : SIG_IGN);
  264. #endif
  265.  
  266.       /* Go for it. */
  267.       execl(sh, argv_zero(sh), "-c", string, (char *) 0);
  268.  
  269.       /* If exec fails, we write a byte to the pipe before exiting. */
  270.       perror(sh);
  271.       write(pfd[1], "", 1);
  272.       _exit(127);
  273.     }
  274.     else {
  275.       int rd;
  276.       char ch;
  277.  
  278.       /* Try to read a byte from the pipe. */
  279.       close(pfd[1]);
  280.       rd = read(pfd[0], &ch, 1);
  281.       close(pfd[0]);
  282.  
  283.       while ((w = wait(&status)) != pid)
  284.           if (w == -1 && errno != EINTR)
  285.           break;
  286.  
  287.       /* If we read a byte from the pipe, the exec failed. */
  288.       if (rd > 0)
  289.         stat = -1;
  290.       else if (w == pid) {
  291. #ifdef    WEXITSTATUS
  292.         stat = WEXITSTATUS(status);
  293. #else
  294. # ifdef    BSD
  295.         stat = status.w_retcode;
  296. # else
  297.         stat = status;
  298. # endif
  299. #endif
  300.       }
  301.       }
  302.  
  303.     (void) signal(SIGINT, istat);
  304.     (void) signal(SIGQUIT, qstat);
  305. #ifdef SIGTSTP
  306.     (void) signal(SIGTSTP, oldstop);
  307.     (void) signal(SIGCONT, oldstart);
  308. #endif
  309.  
  310. #endif  /* OS2 */
  311.  
  312.     return(stat);
  313. }
  314.  
  315. int
  316. do_pipe()
  317. {
  318.     /** pipe the current message or tagged messages to
  319.         the specified sequence.. **/
  320.  
  321.     char command[SLEN], buffer[SLEN], message_list[SLEN];
  322.     register int  ret, to_pipe;
  323.     int    old_raw;
  324.  
  325.     to_pipe = make_msg_list(message_list);
  326.     sprintf(buffer, "Pipe message%s to: ", plural(to_pipe));
  327.         PutLine0(LINES-2,0,buffer);
  328.  
  329.     command[0] = '\0';
  330.  
  331.     (void) optionally_enter(command, LINES-2, strlen(buffer), FALSE, FALSE);
  332.     if (strlen(command) == 0) {
  333.       MoveCursor(LINES-2,0);    CleartoEOLN();
  334.       return(0);
  335.     }
  336.  
  337.     MoveCursor(LINES,0);     CleartoEOLN();
  338.     if (( old_raw = RawState()) == ON)
  339.       Raw(OFF);
  340.  
  341.     if (cursor_control)  transmit_functions(OFF);
  342.  
  343.     sprintf(buffer, "%s -f %s -h %s | %s",
  344.         readmsg,
  345.         (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  346.         message_list,
  347.         command);
  348.  
  349.     ret = system_call(buffer, USER_SHELL, TRUE, TRUE);
  350.  
  351.     SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  352.     PutLine0(LINES, 0, "\n\nPress any key to return to ELM.");
  353.     if (old_raw == ON)
  354.        Raw(ON);
  355.     (void) getchar();
  356.     if (cursor_control)  transmit_functions(ON);
  357.  
  358.     if (ret != 0) error1("Return code was %d.", ret);
  359.     return(1);
  360. }
  361.  
  362. print_msg()
  363. {
  364.     /** Print current message or tagged messages using 'printout'
  365.         variable.  Error message iff printout not defined! **/
  366.  
  367.     char buffer[SLEN], filename[SLEN], printbuffer[SLEN];
  368.     char message_list[SLEN];
  369.     register int  retcode, to_print, cnt;
  370.  
  371.     if (strlen(printout) == 0) {
  372.       error("Don't know how to print - option \"printmail\" undefined!");
  373.       return;
  374.     }
  375.  
  376.     to_print = make_msg_list(message_list);
  377.  
  378.     sprintf(filename,"%s%d%s", temp_dir, getpid(), temp_print);
  379.     os2path(filename);
  380.  
  381.     if (in_string(printout, "%s"))
  382.       sprintf(printbuffer, printout, filename);
  383.     else
  384.       sprintf(printbuffer, "%s %s", printout, filename);
  385.  
  386.     sprintf(buffer,"%s -p -f %s %s >%s & %s 1>nul 2>nul",
  387.         readmsg,
  388.         (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  389.         message_list,
  390.         filename,
  391.         printbuffer);
  392.  
  393.     dprint(2, (debugfile, "Printing system call...\n"));
  394.  
  395.       Centerline(LINES, "Queuing...");
  396.  
  397.     if ((retcode = system_call(buffer, SH, FALSE, FALSE)) == 0) {
  398.       sprintf(buffer, "Message%s queued up to print.", plural(to_print));
  399.       Centerline(LINES, buffer);
  400.     }
  401.     else
  402.       error1("Printout failed with return code %d.", retcode);
  403.  
  404.     unlink(filename);    /* remove da temp file! */
  405. }
  406.  
  407. make_msg_list(message_list)
  408. char *message_list;
  409. {
  410.     /** make a list of the tagged or just the current, if none tagged.
  411.         check for overflow on messsage length
  412.          **/
  413.  
  414.     int i, msgs_selected = 0;
  415.  
  416.     *message_list = '\0';    /* start with an empty list */
  417.  
  418.     for (i=0; i < message_count; i++)
  419.       if (headers[i]->status & TAGGED) {
  420.         if (strlen(message_list) + 6 >= SLEN) {
  421.           error1("Too many messages selected, messages from %d on not used", i);
  422.           return(msgs_selected);
  423.           }
  424.         sprintf(message_list, "%s %d", message_list,
  425.             headers[i]->index_number);
  426.         msgs_selected++;
  427.       }
  428.  
  429.     if (! msgs_selected) {
  430.       sprintf(message_list," %d", headers[current-1]->index_number);
  431.       msgs_selected = 1;
  432.     }
  433.  
  434.     return(msgs_selected);
  435. }
  436.  
  437. list_folders(numlines, helpmsg)
  438. unsigned numlines;
  439. char *helpmsg;
  440. {
  441.     /** list the folders in the users FOLDERHOME directory.  This is
  442.         simply a call to "ls -C"
  443.         Numlines is the number of lines to scroll afterwards. This is
  444.         useful when a portion of the screen needs to be cleared for
  445.         subsequent prompts, but you don't want to overwrite the
  446.         list of folders.
  447.         Helpmsg is what should be printed before the listing if not NULL.
  448.     **/
  449.  
  450.         char buffer[SLEN], foldersbs[SLEN];
  451.  
  452.     Raw(OFF);
  453.     ClearScreen();
  454.     MoveCursor(0, 0);
  455.     if(helpmsg)
  456.       printf(helpmsg);
  457.  
  458.         strcpy(foldersbs,folders);
  459.         os2path(foldersbs);
  460.         sprintf(buffer, "dir /w %s", foldersbs);
  461.  
  462.     printf("\n\rContents of your folder directory:\n\r\n\r");
  463.     system_call(buffer, SH, FALSE, FALSE);
  464.     while(numlines--)
  465.         printf("\n\r");
  466.     Raw(ON);
  467. }
  468.