home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / aix-rs6000 / elm2.3.11.AIX3.1.5.Z / elm2.3.11.AIX3.1.5 / src / syscall.c < prev    next >
C/C++ Source or Header  |  1990-07-12  |  11KB  |  415 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. char *argv_zero();    
  58. void  _exit();
  59.  
  60. #ifdef ALLOW_SUBSHELL
  61.  
  62. int
  63. subshell()
  64. {
  65.     /** spawn a subshell with either the specified command
  66.         returns non-zero if screen rewrite needed
  67.     **/
  68.  
  69.     char command[SLEN];
  70.     int  old_raw, helpful, ret;
  71.  
  72.     helpful = (user_level == 0);
  73.  
  74.     if (helpful)
  75.       PutLine0(LINES-3,COLUMNS-40,"(Use the shell name for a shell.)");
  76.     PutLine0(LINES-2,0,"Shell command: ");
  77.     CleartoEOS();
  78.     command[0] = '\0';
  79.     (void) optionally_enter(command, LINES-2, 15, FALSE, FALSE);
  80.     if (command[0] == 0) {
  81.       if (helpful)
  82.         MoveCursor(LINES-3,COLUMNS-40);
  83.       else
  84.         MoveCursor(LINES-2,0);
  85.       CleartoEOS();
  86.       return 0;
  87.     }
  88.  
  89.     MoveCursor(LINES,0);
  90.     CleartoEOLN();
  91.  
  92.     if ((old_raw = RawState()) == ON)
  93.       Raw(OFF);
  94.     softkeys_off();
  95.     if (cursor_control)
  96.       transmit_functions(OFF);
  97.     
  98.     umask(original_umask);    /* restore original umask so users new files are ok */
  99.     ret = system_call(command, USER_SHELL, TRUE, TRUE);
  100.     umask(077);        /* now put it back to private for mail files */
  101.  
  102.     SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  103.     PutLine0(LINES, 0, "\n\nPress any key to return to ELM: ");
  104.     Raw(ON);
  105.     (void) getchar();
  106.     if (old_raw == OFF)
  107.       Raw(OFF);
  108.     softkeys_on();
  109.     if (cursor_control)
  110.       transmit_functions(ON);
  111.  
  112.     if (ret)
  113.       error1("Return code was %d.", ret);
  114.  
  115.     return 1;
  116. }
  117.  
  118. #endif /* ALLOW_SUBSHELL */
  119.  
  120. system_call(string, shell_type, allow_signals, allow_interrupt)
  121. char *string;
  122. int   shell_type, allow_signals, allow_interrupt;
  123. {
  124.     /** execute 'string', setting uid to userid... **/
  125.     /** if shell-type is "SH" /bin/sh is used regardless of the 
  126.         users shell setting.  Otherwise, "USER_SHELL" is sent.
  127.         If allow_signals is TRUE, then allow the executed
  128.         command handle hangup, and optionally if allow_interrupt
  129.         is also true handle interrupt in its own way.
  130.         This is useful for executed programs with
  131.         user interaction that handle those signals on their
  132.         own terms. It is especially important for vi, so that
  133.         a message being edited when a user connection is
  134.         dropped is recovered by vi's expreserve program **/
  135.  
  136.     int pfd[2], stat, pid, w, iteration;
  137.     char *sh;
  138. #if defined(BSD) && !defined(WEXITSTATUS)
  139.     union wait status;
  140. #else
  141.     int status;
  142. #endif
  143. #ifdef VOIDSIG
  144.     register void (*istat)(), (*qstat)();
  145. # ifdef SIGTSTP
  146.     register void (*oldstop)(), (*oldstart)();
  147. # endif
  148. #else
  149.     register int (*istat)(), (*qstat)();
  150. # ifdef SIGTSTP
  151.     register int (*oldstop)(), (*oldstart)();
  152. # endif 
  153. #endif
  154.     extern int errno;
  155.  
  156.     sh = (shell_type == USER_SHELL) ? shell : "/bin/sh";
  157.     dprint(2, (debugfile, "System Call: %s\n\t%s\n", sh, string));
  158.  
  159.     /*
  160.      * Note the neat trick with close-on-exec pipes.
  161.      * If the child's exec() succeeds, then the pipe read returns zero.
  162.      * Otherwise, it returns the zero byte written by the child
  163.      * after the exec() is attempted.  This is the cleanest way I know
  164.      * to discover whether an exec() failed.   --CHS
  165.      */
  166.  
  167.     if (pipe(pfd) == -1) {
  168.       perror("pipe");
  169.       return -1;
  170.     }
  171.     fcntl(pfd[0], F_SETFD, 1);
  172.     fcntl(pfd[1], F_SETFD, 1);
  173.  
  174.     istat = signal(SIGINT, SIG_IGN);
  175.     qstat = signal(SIGQUIT, SIG_IGN);
  176. #ifdef SIGTSTP
  177.     oldstop = signal(SIGTSTP, SIG_DFL);
  178.     oldstart = signal(SIGCONT, SIG_DFL);
  179. #endif
  180.  
  181.     stat = -1;        /* Assume failure. */
  182.  
  183.     for (iteration = 0; iteration < 5; ++iteration) {
  184.       if (iteration > 0)
  185.         sleep(2);
  186.  
  187. #ifdef VFORK
  188.       pid = vfork();
  189. #else
  190.       pid = fork();
  191. #endif
  192.  
  193.       if (pid != -1)
  194.         break;
  195.     }
  196.  
  197.     if (pid == -1) {
  198.       perror("fork");
  199.     }
  200.     else if (pid == 0) {
  201.       /*
  202.        * Set group and user back to their original values.
  203.        * Note that group must be set first.
  204.        */
  205.       setgid(groupid);
  206.       setuid(userid);
  207.  
  208.       /*
  209.        * Program to exec may or may not be able to handle
  210.        * interrupt, quit, hangup and stop signals.
  211.        */
  212.       (void) signal(SIGHUP, allow_signals ? SIG_DFL : SIG_IGN);
  213.       (void) signal(SIGINT, (allow_signals && allow_interrupt)?SIG_DFL:SIG_IGN);
  214.       (void) signal(SIGQUIT, (allow_signals && allow_interrupt)?SIG_DFL:SIG_IGN);
  215. #ifdef SIGTSTP
  216.       (void) signal(SIGTSTP, allow_signals ? SIG_DFL : SIG_IGN);
  217.       (void) signal(SIGCONT, allow_signals ? SIG_DFL : SIG_IGN);
  218. #endif
  219.  
  220.       /* Go for it. */
  221.       execl(sh, argv_zero(sh), "-c", string, (char *) 0);
  222.  
  223.       /* If exec fails, we write a byte to the pipe before exiting. */
  224.       perror(sh);
  225.       write(pfd[1], "", 1);
  226.       _exit(127);
  227.     }
  228.     else {
  229.       int rd;
  230.       char ch;
  231.  
  232.       /* Try to read a byte from the pipe. */
  233.       close(pfd[1]);
  234.       rd = read(pfd[0], &ch, 1);
  235.       close(pfd[0]);
  236.  
  237.       while ((w = wait(&status)) != pid)
  238.           if (w == -1 && errno != EINTR)
  239.           break;
  240.  
  241.       /* If we read a byte from the pipe, the exec failed. */
  242.       if (rd > 0)
  243.         stat = -1;
  244.       else if (w == pid) {
  245. #ifdef    WEXITSTATUS
  246.         stat = WEXITSTATUS(status);
  247. #else
  248. # ifdef    BSD
  249.         stat = status.w_retcode;
  250. # else
  251.         stat = status;
  252. # endif
  253. #endif
  254.       }
  255.       }
  256.   
  257.     (void) signal(SIGINT, istat);
  258.     (void) signal(SIGQUIT, qstat);
  259. #ifdef SIGTSTP
  260.     (void) signal(SIGTSTP, oldstop);
  261.     (void) signal(SIGCONT, oldstart);
  262. #endif
  263.  
  264.     return(stat);
  265. }
  266.  
  267. int
  268. do_pipe()
  269. {
  270.     /** pipe the current message or tagged messages to
  271.         the specified sequence.. **/
  272.  
  273.     char command[SLEN], buffer[SLEN], message_list[SLEN];
  274.     register int  ret, to_pipe;
  275.     int    old_raw;
  276.  
  277.     to_pipe = make_msg_list(message_list);
  278.     sprintf(buffer, "Pipe message%s to: ", plural(to_pipe));
  279.         PutLine0(LINES-2,0,buffer);
  280.  
  281.     command[0] = '\0';
  282.  
  283.     (void) optionally_enter(command, LINES-2, strlen(buffer), FALSE, FALSE);
  284.     if (strlen(command) == 0) {
  285.       MoveCursor(LINES-2,0);    CleartoEOLN();
  286.       return(0);
  287.     }
  288.  
  289.     MoveCursor(LINES,0);     CleartoEOLN();
  290.     if (( old_raw = RawState()) == ON)
  291.       Raw(OFF);
  292.  
  293.     if (cursor_control)  transmit_functions(OFF);
  294.     
  295.     sprintf(buffer, "%s -f %s -h %s | %s",
  296.         readmsg,
  297.         (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  298.         message_list,
  299.         command);
  300.     
  301.     ret = system_call(buffer, USER_SHELL, TRUE, TRUE);
  302.  
  303.     SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  304.     PutLine0(LINES, 0, "\n\nPress any key to return to ELM.");
  305.     if (old_raw == ON)
  306.        Raw(ON);
  307.     (void) getchar();
  308.     if (cursor_control)  transmit_functions(ON);
  309.  
  310.     if (ret != 0) error1("Return code was %d.", ret);
  311.     return(1);
  312. }
  313.  
  314. print_msg()
  315. {
  316.     /** Print current message or tagged messages using 'printout' 
  317.         variable.  Error message iff printout not defined! **/
  318.  
  319.     char buffer[SLEN], filename[SLEN], printbuffer[SLEN];
  320.     char message_list[SLEN];
  321.     register int  retcode, to_print;
  322.  
  323.     if (strlen(printout) == 0) {
  324.       error("Don't know how to print - option \"printmail\" undefined!");
  325.       return;
  326.     }
  327.     
  328.     to_print = make_msg_list(message_list);
  329.  
  330.     sprintf(filename,"%s%s%d", temp_dir, temp_print, getpid());
  331.  
  332.     if (in_string(printout, "%s"))
  333.       sprintf(printbuffer, printout, filename);
  334.     else
  335.       sprintf(printbuffer, "%s %s", printout, filename);
  336.  
  337.     sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null",
  338.         readmsg,
  339.         (folder_type == NON_SPOOL ? cur_folder : cur_tempfolder),
  340.         message_list, 
  341.         filename,
  342.         printbuffer);
  343.     
  344.     dprint(2, (debugfile, "Printing system call...\n"));
  345.  
  346.       Centerline(LINES, "Queuing...");
  347.  
  348.     if ((retcode = system_call(buffer, SH, FALSE, FALSE)) == 0) {
  349.       sprintf(buffer, "Message%s queued up to print.", plural(to_print));
  350.       Centerline(LINES, buffer);
  351.     }
  352.     else
  353.       error1("Printout failed with return code %d.", retcode);
  354.  
  355.     unlink(filename);    /* remove da temp file! */
  356. }
  357.  
  358. make_msg_list(message_list)
  359. char *message_list;
  360. {
  361.     /** make a list of the tagged or just the current, if none tagged.
  362.         check for overflow on messsage length
  363.          **/
  364.  
  365.     int i, msgs_selected = 0;
  366.  
  367.     *message_list = '\0';    /* start with an empty list */
  368.  
  369.     for (i=0; i < message_count; i++) 
  370.       if (headers[i]->status & TAGGED) {
  371.         if (strlen(message_list) + 6 >= SLEN) {
  372.           error1("Too many messages selected, messages from %d on not used", i);
  373.           return(msgs_selected);
  374.           }
  375.         sprintf(message_list, "%s %d", message_list, 
  376.             headers[i]->index_number);
  377.         msgs_selected++;
  378.       }
  379.  
  380.     if (! msgs_selected) {
  381.       sprintf(message_list," %d", headers[current-1]->index_number);
  382.       msgs_selected = 1;
  383.     }
  384.     
  385.     return(msgs_selected);
  386. }
  387.  
  388. list_folders(numlines, helpmsg)
  389. unsigned numlines;
  390. char *helpmsg;
  391. {
  392.     /** list the folders in the users FOLDERHOME directory.  This is
  393.         simply a call to "ls -C"
  394.         Numlines is the number of lines to scroll afterwards. This is
  395.         useful when a portion of the screen needs to be cleared for
  396.         subsequent prompts, but you don't want to overwrite the
  397.         list of folders.
  398.         Helpmsg is what should be printed before the listing if not NULL.
  399.     **/
  400.  
  401.     char buffer[SLEN];
  402.  
  403.     Raw(OFF);
  404.     ClearScreen();
  405.     MoveCursor(LINES, 0);
  406.     if(helpmsg)
  407.       printf(helpmsg);
  408.     sprintf(buffer, "cd %s;ls -C", folders);
  409.     printf("\n\rContents of your folder directory:\n\r\n\r");
  410.     system_call(buffer, SH, FALSE, FALSE); 
  411.     while(numlines--)
  412.         printf("\n\r");
  413.     Raw(ON);
  414. }
  415.