* serial.h (SERIAL_SET_TTY_STATE): Comment return value.
[deliverable/binutils-gdb.git] / gdb / procfs.c
index 5ebc5e047eacab29dc81559fd6616e69c5f13981..0d7aee8775787c277ab58c70bba6bc0a11e145e2 100644 (file)
@@ -34,6 +34,7 @@ regardless of whether or not the actual target has floating point hardware.
 
 #include "defs.h"
 
+#include <sys/types.h>
 #include <time.h>
 #include <sys/procfs.h>
 #include <fcntl.h>
@@ -41,6 +42,8 @@ regardless of whether or not the actual target has floating point hardware.
 #include <string.h>
 #include <stropts.h>
 #include <poll.h>
+#include <unistd.h>
+#include <sys/stat.h>
 
 #include "inferior.h"
 #include "target.h"
@@ -1206,36 +1209,6 @@ init_syscall_table ()
 
 /*
 
-GLOBAL FUNCTION
-
-       ptrace -- override library version to force errors for /proc version
-
-SYNOPSIS
-
-       int ptrace (int request, int pid, PTRACE_ARG3_TYPE arg3, int arg4)
-
-DESCRIPTION
-
-       When gdb is configured to use /proc, it should not be calling
-       or otherwise attempting to use ptrace.  In order to catch errors
-       where use of /proc is configured, but some routine is still calling
-       ptrace, we provide a local version of a function with that name
-       that does nothing but issue an error message.
-*/
-
-int
-ptrace (request, pid, arg3, arg4)
-     int request;
-     int pid;
-     PTRACE_ARG3_TYPE arg3;
-     int arg4;
-{
-  error ("internal error - there is a call to ptrace() somewhere");
-  /*NOTREACHED*/
-}
-
-/*
-
 LOCAL FUNCTION
 
        procfs_kill_inferior - kill any currently inferior
@@ -2174,48 +2147,33 @@ do_detach (signal)
   attach_flag = 0;
 }
 
-/*
-
-LOCAL FUNCTION
-
-       procfs_wait -- emulate wait() as much as possible
-       Wait for child to do something.  Return pid of child, or -1 in case
-       of error; store status through argument pointer STATUS.
-
-
-SYNOPSIS
-
-       int procfs_wait (int pid, int *statloc)
-
-DESCRIPTION
-
-       Try to emulate wait() as much as possible.  Not sure why we can't
-       just use wait(), but it seems to have problems when applied to a
-       process being controlled with the /proc interface.
-
-NOTES
-
-       We have a race problem here with no obvious solution.  We need to let
-       the inferior run until it stops on an event of interest, which means
-       that we need to use the PIOCWSTOP ioctl.  However, we cannot use this
-       ioctl if the process is already stopped on something that is not an
-       event of interest, or the call will hang indefinitely.  Thus we first
-       use PIOCSTATUS to see if the process is not stopped.  If not, then we
-       use PIOCWSTOP.  But during the window between the two, if the process
-       stops for any reason that is not an event of interest (such as a job
-       control signal) then gdb will hang.  One possible workaround is to set
-       an alarm to wake up every minute of so and check to see if the process
-       is still running, and if so, then reissue the PIOCWSTOP.  But this is
-       a real kludge, so has not been implemented.  FIXME: investigate
-       alternatives.
-
-       FIXME:  Investigate why wait() seems to have problems with programs
-       being control by /proc routines.
-
- */
+/*  emulate wait() as much as possible.
+    Wait for child to do something.  Return pid of child, or -1 in case
+    of error; store status in *OURSTATUS.
+
+    Not sure why we can't
+    just use wait(), but it seems to have problems when applied to a
+    process being controlled with the /proc interface.
+
+    We have a race problem here with no obvious solution.  We need to let
+    the inferior run until it stops on an event of interest, which means
+    that we need to use the PIOCWSTOP ioctl.  However, we cannot use this
+    ioctl if the process is already stopped on something that is not an
+    event of interest, or the call will hang indefinitely.  Thus we first
+    use PIOCSTATUS to see if the process is not stopped.  If not, then we
+    use PIOCWSTOP.  But during the window between the two, if the process
+    stops for any reason that is not an event of interest (such as a job
+    control signal) then gdb will hang.  One possible workaround is to set
+    an alarm to wake up every minute of so and check to see if the process
+    is still running, and if so, then reissue the PIOCWSTOP.  But this is
+    a real kludge, so has not been implemented.  FIXME: investigate
+    alternatives.
+
+    FIXME:  Investigate why wait() seems to have problems with programs
+    being control by /proc routines.  */
 
 static int
-procfs_wait (pid, statloc)
+procfs_wait (pid, ourstatus)
      int pid;
      struct target_waitstatus *ourstatus;
 {
@@ -3463,8 +3421,78 @@ procfs_create_inferior (exec_file, allargs, env)
      char *allargs;
      char **env;
 {
+  char *shell_file = getenv ("SHELL");
+  char *tryname;
+  if (shell_file != NULL && strchr (shell_file, '/') == NULL)
+    {
+
+      /* We will be looking down the PATH to find shell_file.  If we
+        just do this the normal way (via execlp, which operates by
+        attempting an exec for each element of the PATH until it
+        finds one which succeeds), then there will be an exec for
+        each failed attempt, each of which will cause a PR_SYSEXIT
+        stop, and we won't know how to distinguish the PR_SYSEXIT's
+        for these failed execs with the ones for successful execs
+        (whether the exec has succeeded is stored at that time in the
+        carry bit or some such architecture-specific and
+        non-ABI-specified place).
+
+        So I can't think of anything better than to search the PATH
+        now.  This has several disadvantages: (1) There is a race
+        condition; if we find a file now and it is deleted before we
+        exec it, we lose, even if the deletion leaves a valid file
+        further down in the PATH, (2) there is no way to know exactly
+        what an executable (in the sense of "capable of being
+        exec'd") file is.  Using access() loses because it may lose
+        if the caller is the superuser; failing to use it loses if
+        there are ACLs or some such.  */
+
+      char *p;
+      char *p1;
+      /* FIXME-maybe: might want "set path" command to replace putenv hack
+        in set_in_environ.  */
+      char *path = getenv ("PATH");
+      int len;
+      struct stat statbuf;
+
+      if (path == NULL)
+       path = "/bin:/usr/bin";
+
+      tryname = alloca (strlen (path) + strlen (shell_file) + 2);
+      for (p = path; p != NULL; p = p1 ? p1 + 1: NULL)
+       {
+         p1 = strchr (p, ':');
+         if (p1 != NULL)
+           len = p1 - p;
+         else
+           len = strlen (p);
+         strncpy (tryname, p, len);
+         tryname[len] = '\0';
+         strcat (tryname, "/");
+         strcat (tryname, shell_file);
+         if (access (tryname, X_OK) < 0)
+           continue;
+         if (stat (tryname, &statbuf) < 0)
+           continue;
+         if (!S_ISREG (statbuf.st_mode))
+           /* We certainly need to reject directories.  I'm not quite
+              as sure about FIFOs, sockets, etc., but I kind of doubt
+              that people want to exec() these things.  */
+           continue;
+         break;
+       }
+      if (p == NULL)
+       /* Not found.  This must be an error rather than merely passing
+          the file to execlp(), because execlp() would try all the
+          exec()s, causing GDB to get confused.  */
+       error ("Can't find shell %s in PATH", shell_file);
+
+      shell_file = tryname;
+    }
+
   fork_inferior (exec_file, allargs, env,
-                proc_set_exec_trap, procfs_init_inferior);
+                proc_set_exec_trap, procfs_init_inferior, shell_file);
+
   /* We are at the first instruction we care about.  */
   /* Pedal to the metal... */
 
This page took 0.025042 seconds and 4 git commands to generate.