(root)/
gcc-13.2.0/
fixincludes/
server.c
       1  
       2  /*
       3   *  server.c  Set up and handle communications with a server process.
       4   *
       5   *  Server Handling copyright 1992-1999, 2001 The Free Software Foundation
       6   *
       7   *  Server Handling is free software.
       8   *  You may redistribute it and/or modify it under the terms of the
       9   *  GNU General Public License, as published by the Free Software
      10   *  Foundation; either version 2, or (at your option) any later version.
      11   *
      12   *  Server Handling is distributed in the hope that it will be useful,
      13   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15   *  GNU General Public License for more details.
      16   *
      17   *  You should have received a copy of the GNU General Public License
      18   *  along with Server Handling.  See the file "COPYING".  If not,
      19   *  write to:  The Free Software Foundation, Inc.,
      20   *             51 Franklin Street, Fifth Floor,
      21   *             Boston,  MA  02110-1301, USA.
      22   *
      23   * As a special exception, The Free Software Foundation gives
      24   * permission for additional uses of the text contained in his release
      25   * of ServerHandler.
      26   *
      27   * The exception is that, if you link the ServerHandler library with other
      28   * files to produce an executable, this does not by itself cause the
      29   * resulting executable to be covered by the GNU General Public License.
      30   * Your use of that executable is in no way restricted on account of
      31   * linking the ServerHandler library code into it.
      32   *
      33   * This exception does not however invalidate any other reasons why
      34   * the executable file might be covered by the GNU General Public License.
      35   *
      36   * This exception applies only to the code released by The Free
      37   * Software Foundation under the name ServerHandler.  If you copy code
      38   * from other sources under the General Public License into a copy of
      39   * ServerHandler, as the General Public License permits, the exception
      40   * does not apply to the code that you add in this way.  To avoid
      41   * misleading anyone as to the status of such modified files, you must
      42   * delete this exception notice from them.
      43   *
      44   * If you write modifications of your own for ServerHandler, it is your
      45   * choice whether to permit this exception to apply to your modifications.
      46   * If you do not wish that, delete this exception notice.
      47   */
      48  
      49  #include "fixlib.h"
      50  #include "server.h"
      51  
      52  STATIC volatile enum t_bool read_pipe_timeout;
      53  STATIC pid_t server_master_pid = NOPROCESS;
      54  
      55  tSCC* def_args[] =
      56  { (char *) NULL, (char *) NULL };
      57  STATIC t_pf_pair server_pair =
      58  { (FILE *) NULL, (FILE *) NULL };
      59  STATIC pid_t server_id = NULLPROCESS;
      60  /*
      61   *  Arbitrary text that should not be found in the shell output.
      62   *  It must be a single line and appear verbatim at the start of
      63   *  the terminating output line.
      64   */
      65  tSCC z_done[] = "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd";
      66  tSCC* p_cur_dir = (char *) NULL;
      67  
      68  /*
      69   *  load_data
      70   *
      71   *  Read data from a file pointer (a pipe to a process in this context)
      72   *  until we either get EOF or we get a marker line back.
      73   *  The read data are stored in a malloc-ed string that is truncated
      74   *  to size at the end.  Input is assumed to be an ASCII string.
      75   */
      76  static char *
      77  load_data (FILE* fp)
      78  {
      79    char *pz_text;
      80    size_t text_size;
      81    char *pz_scan;
      82    char z_line[1024];
      83    t_bool got_done = BOOL_FALSE;
      84  
      85    text_size = sizeof (z_line) * 2;
      86    pz_scan = pz_text = XNEWVEC (char, text_size);
      87  
      88    for (;;)
      89      {
      90        size_t used_ct;
      91  
      92        alarm (10);
      93        read_pipe_timeout = BOOL_FALSE;
      94        if (fgets (z_line, sizeof (z_line), fp) == (char *) NULL)
      95          break;
      96  
      97        if (strncmp (z_line, z_done, sizeof (z_done) - 1) == 0)
      98  	{
      99  	  got_done = BOOL_TRUE;
     100  	  break;
     101  	}
     102  
     103        strcpy (pz_scan, z_line);
     104        pz_scan += strlen (z_line);
     105        used_ct = (size_t) (pz_scan - pz_text);
     106  
     107        if (text_size - used_ct < sizeof (z_line))
     108          {
     109            size_t off = (size_t) (pz_scan - pz_text);
     110  	  
     111            text_size += 4096;
     112            pz_text = XRESIZEVEC (char, pz_text, text_size);
     113            pz_scan = pz_text + off;
     114          }
     115      }
     116  
     117    alarm (0);
     118    if (read_pipe_timeout || ! got_done)
     119      {
     120        free ((void *) pz_text);
     121        return (char *) NULL;
     122      }
     123  
     124    while ((pz_scan > pz_text) && ISSPACE (pz_scan[-1]))
     125      pz_scan--;
     126    *pz_scan = NUL;
     127    return XRESIZEVEC (char, pz_text, strlen (pz_text) + 1);
     128  }
     129  
     130  
     131  /*
     132   *  close_server
     133   *
     134   *  Make certain the server process is dead, close the 
     135   *  pipes to it and from it, finally NULL out the file pointers
     136   */
     137  void
     138  close_server (void)
     139  {
     140    if (  (server_id != NULLPROCESS)
     141       && (server_master_pid == getpid ()))
     142      {
     143        kill ((pid_t) server_id, SIGKILL);
     144        server_id = NULLPROCESS;
     145        server_master_pid = NOPROCESS;
     146        fclose (server_pair.pf_read);
     147        fclose (server_pair.pf_write);
     148        server_pair.pf_read = server_pair.pf_write = (FILE *) NULL;
     149      }
     150  }
     151  
     152  /*
     153   *  sig_handler really only handles the timeout and pipe signals.
     154   *  This ensures that we do not wait forever on a request
     155   *  to our server, and also that if the server dies, we do not
     156   *  die from a sigpipe problem.
     157   */
     158  static void
     159  sig_handler (int signo ATTRIBUTE_UNUSED)
     160  {
     161  #ifdef DEBUG
     162    /* FIXME: this is illegal to do in a signal handler.  */
     163    fprintf (stderr,
     164            "fixincl ERROR:  sig_handler: killed pid %ld due to %s\n",
     165            (long) server_id, signo == SIGPIPE ? "SIGPIPE" : "SIGALRM");
     166  #endif
     167    close_server ();
     168    read_pipe_timeout = BOOL_TRUE;
     169  }
     170  
     171  
     172  /*
     173   *  server_setup  Establish the signal handler for PIPE and ALARM.
     174   *  Also establishes the current directory to give to the
     175   *  server process at the start of every server command.
     176   */
     177  static void
     178  server_setup (void)
     179  {
     180    static int atexit_done = 0;
     181    char buff [MAXPATHLEN + 1];
     182    
     183    if (atexit_done++ == 0)
     184      atexit (close_server);
     185    else
     186      fputs ("NOTE: server restarted\n", stderr);
     187  
     188    server_master_pid = getpid ();
     189  
     190    signal (SIGPIPE, sig_handler);
     191    signal (SIGALRM, sig_handler);
     192  
     193    fputs ("trap : 1\n", server_pair.pf_write);
     194    fflush (server_pair.pf_write);
     195    if (getcwd (buff, MAXPATHLEN + 1) == NULL)
     196      buff[0] = 0;
     197    p_cur_dir = xstrdup (buff);
     198  }
     199  
     200  /*
     201   *  find_shell
     202   *
     203   *  Locate a shell suitable for use.  For various reasons
     204   *  (like the use of "trap" in server_setup(), it must be a
     205   *  Bourne-like shell.
     206   *
     207   *  Most of the time, /bin/sh is preferred, but sometimes
     208   *  it's quite broken (like on Ultrix).  autoconf lets you
     209   *  override with $CONFIG_SHELL, so we do the same.
     210   */
     211  
     212  static const char *
     213  find_shell (void)
     214  {
     215    char * shell = getenv ("CONFIG_SHELL");
     216    if (shell)
     217      return shell;
     218  
     219    return "/bin/sh";
     220  }
     221  
     222  
     223  /*
     224   *  run_shell
     225   *
     226   *  Run a shell command on the server.  The command string
     227   *  passed in is wrapped inside the sequence:
     228   *
     229   *     cd <original directory>
     230   *     <command string>
     231   *     echo
     232   *     echo <end-of-command-marker>
     233   *
     234   *  This ensures that all commands start at a known place in
     235   *  the directory structure, that any incomplete output lines
     236   *  are completed and that our special marker sequence appears on
     237   *  a line by itself.  We have chosen a marker that is
     238   *  excessively unlikely to be reproduced in normal output:
     239   *
     240   *     "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd"
     241   */
     242  char *
     243  run_shell (const char* pz_cmd)
     244  {
     245    tSCC zNoServer[] = "Server not running, cannot run:\n%s\n\n";
     246    t_bool retry = BOOL_TRUE;
     247  
     248   do_retry:
     249    /*  IF the shell server process is not running yet,
     250        THEN try to start it.  */
     251    if (server_id == NULLPROCESS)
     252      {
     253        def_args[0] = find_shell ();
     254  
     255        server_id = proc2_fopen (&server_pair, def_args);
     256        if (server_id > 0)
     257          server_setup ();
     258      }
     259  
     260    /*  IF it is still not running, THEN return the nil string.  */
     261    if (server_id <= 0)
     262      {
     263        fprintf (stderr, zNoServer, pz_cmd);
     264        return XCNEW (char);
     265      }
     266  
     267    /*  Make sure the process will pay attention to us, send the
     268       supplied command, and then have it output a special marker that
     269       we can find.  */
     270    fprintf (server_pair.pf_write, "cd \"%s\"\n%s\n\necho\necho %s\n",
     271             p_cur_dir, pz_cmd, z_done);
     272    fflush (server_pair.pf_write);
     273  
     274    /*  IF the server died and we received a SIGPIPE,
     275        THEN return an empty string.  */
     276    if (server_id == NULLPROCESS)
     277      {
     278        fprintf (stderr, zNoServer, pz_cmd);
     279        return XCNEW (char);
     280      }
     281  
     282    /*  Now try to read back all the data.  If we fail due to either a
     283       sigpipe or sigalrm (timeout), we will return the nil string.  */
     284    {
     285      char *pz = load_data (server_pair.pf_read);
     286      
     287      if (pz == (char *) NULL)
     288        {
     289  	close_server ();
     290  
     291  	if (retry)
     292  	  {
     293  	    retry = BOOL_FALSE;
     294  	    goto do_retry;
     295  	  }
     296  
     297          fprintf (stderr, "CLOSING SHELL SERVER - command failure:\n\t%s\n",
     298                   pz_cmd);
     299          pz = XCNEW (char);
     300        }
     301  #ifdef DEBUG
     302      fprintf( stderr, "run_shell command success:  %s\n", pz );
     303  #endif
     304      return pz;
     305    }
     306  }