Try to solve the problem of spurious EOF chars in long lines of text
[bpt/emacs.git] / src / process.c
index 413bd85..7e8f4cc 100644 (file)
@@ -1,7 +1,7 @@
 /* Asynchronous subprocess control for GNU Emacs.
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995,
-                 1996, 1998, 1999, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+                1996, 1998, 1999, 2001, 2002, 2003, 2004,
+                2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -38,17 +38,18 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/types.h>         /* some typedefs are used in sys/file.h */
 #include <sys/file.h>
 #include <sys/stat.h>
+#include <setjmp.h>
 #ifdef HAVE_INTTYPES_H
 #include <inttypes.h>
 #endif
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-
-#if defined(WINDOWSNT) || defined(UNIX98_PTYS)
-#include <stdlib.h>
 #include <fcntl.h>
-#endif /* not WINDOWSNT */
 
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
@@ -68,21 +69,12 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 #endif /* HAVE_SOCKETS */
 
-/* TERM is a poor-man's SLIP, used on GNU/Linux.  */
-#ifdef TERM
-#include <client.h>
-#endif
-
-#if defined(BSD_SYSTEM)
+#if defined(HAVE_SYS_IOCTL_H)
 #include <sys/ioctl.h>
 #if !defined (O_NDELAY) && defined (HAVE_PTYS) && !defined(USG5)
 #include <fcntl.h>
 #endif /* HAVE_PTYS and no O_NDELAY */
-#endif /* BSD_SYSTEM */
-
-#ifdef BROKEN_O_NONBLOCK
-#undef O_NONBLOCK
-#endif /* BROKEN_O_NONBLOCK */
+#endif /* HAVE_SYS_IOCTL_H */
 
 #ifdef NEED_BSDTTY
 #include <bsdtty.h>
@@ -99,10 +91,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #endif
 #endif
 
-#ifdef IRIS
-#include <sys/sysmacros.h>     /* for "minor" */
-#endif /* not IRIS */
-
 #ifdef HAVE_SYS_WAIT
 #include <sys/wait.h>
 #endif
@@ -132,13 +120,21 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "composite.h"
 #include "atimer.h"
 
+#if defined (USE_GTK) || defined (HAVE_GCONF)
+#include "xgselect.h"
+#endif /* defined (USE_GTK) || defined (HAVE_GCONF) */
+
 Lisp_Object Qprocessp;
 Lisp_Object Qrun, Qstop, Qsignal;
 Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten;
-Lisp_Object Qlocal, Qipv4, Qdatagram;
+Lisp_Object Qlocal, Qipv4, Qdatagram, Qseqpacket;
+Lisp_Object Qreal, Qnetwork, Qserial;
 #ifdef AF_INET6
 Lisp_Object Qipv6;
 #endif
+Lisp_Object QCport, QCspeed, QCprocess;
+Lisp_Object QCbytesize, QCstopbits, QCparity, Qodd, Qeven;
+Lisp_Object QCflowcontrol, Qhw, Qsw, QCsummary;
 Lisp_Object QCname, QCbuffer, QChost, QCservice, QCtype;
 Lisp_Object QClocal, QCremote, QCcoding;
 Lisp_Object QCserver, QCnowait, QCnoquery, QCstop;
@@ -155,23 +151,25 @@ extern Lisp_Object QCfamily;
 /* QCfilter is defined in keyboard.c.  */
 extern Lisp_Object QCfilter;
 
-/* a process object is a network connection when its childp field is neither
-   Qt nor Qnil but is instead a property list (KEY VAL ...).  */
+Lisp_Object Qeuid, Qegid, Qcomm, Qstate, Qppid, Qpgrp, Qsess, Qttname, Qtpgid;
+Lisp_Object Qminflt, Qmajflt, Qcminflt, Qcmajflt, Qutime, Qstime, Qcstime;
+Lisp_Object Qcutime, Qpri, Qnice, Qthcount, Qstart, Qvsize, Qrss, Qargs;
+Lisp_Object Quser, Qgroup, Qetime, Qpcpu, Qpmem, Qtime, Qctime;
 
 #ifdef HAVE_SOCKETS
-#define NETCONN_P(p) (CONSP (XPROCESS (p)->childp))
-#define NETCONN1_P(p) (CONSP ((p)->childp))
+#define NETCONN_P(p) (EQ (XPROCESS (p)->type, Qnetwork))
+#define NETCONN1_P(p) (EQ ((p)->type, Qnetwork))
+#define SERIALCONN_P(p) (EQ (XPROCESS (p)->type, Qserial))
+#define SERIALCONN1_P(p) (EQ ((p)->type, Qserial))
 #else
 #define NETCONN_P(p) 0
 #define NETCONN1_P(p) 0
+#define SERIALCONN_P(p) 0
+#define SERIALCONN1_P(p) 0
 #endif /* HAVE_SOCKETS */
 
 /* Define first descriptor number available for subprocesses.  */
-#ifdef VMS
-#define FIRST_PROC_DESC 1
-#else /* Not VMS */
 #define FIRST_PROC_DESC 3
-#endif
 
 /* Define SIGCHLD as an alias for SIGCLD.  There are many conditionals
    testing SIGCHLD.  */
@@ -186,11 +184,15 @@ extern Lisp_Object QCfilter;
 
 extern char *get_operating_system_release ();
 
-#ifndef USE_CRT_DLL
-extern int errno;
+/* Serial processes require termios or Windows.  */
+#if defined (HAVE_TERMIOS) || defined (WINDOWSNT)
+#define HAVE_SERIAL
 #endif
-#ifdef VMS
-extern char *sys_errlist[];
+
+#ifdef HAVE_SERIAL
+/* From sysdep.c or w32.c  */
+extern int serial_open (char *port);
+extern void serial_configure (struct Lisp_Process *p, Lisp_Object contact);
 #endif
 
 #ifndef HAVE_H_ERRNO
@@ -247,9 +249,8 @@ int update_tick;
 #endif /* DATAGRAM_SOCKETS */
 #endif /* BROKEN_DATAGRAM_SOCKETS */
 
-#ifdef TERM
-#undef NON_BLOCKING_CONNECT
-#undef DATAGRAM_SOCKETS
+#if defined HAVE_LOCAL_SOCKETS && defined DATAGRAM_SOCKETS
+# define HAVE_SEQPACKET
 #endif
 
 #if !defined (ADAPTIVE_READ_BUFFERING) && !defined (NO_ADAPTIVE_READ_BUFFERING)
@@ -288,6 +289,7 @@ static int keyboard_bit_set P_ ((SELECT_TYPE *));
 static void deactivate_process P_ ((Lisp_Object));
 static void status_notify P_ ((struct Lisp_Process *));
 static int read_process_output P_ ((Lisp_Object, int));
+static void create_pty P_ ((Lisp_Object));
 
 /* If we support a window system, turn on the code to poll periodically
    to detect C-g.  It isn't actually used when doing interrupt input.  */
@@ -298,7 +300,6 @@ static int read_process_output P_ ((Lisp_Object, int));
 static Lisp_Object get_process ();
 static void exec_sentinel ();
 
-extern EMACS_TIME timer_check ();
 extern int timers_run;
 \f
 /* Mask of bits indicating the descriptors that we wait for input on.  */
@@ -395,16 +396,14 @@ static char pty_name[24];
 /* Compute the Lisp form of the process status, p->status, from
    the numeric status that was returned by `wait'.  */
 
-static Lisp_Object status_convert ();
+static Lisp_Object status_convert (int);
 
 static void
 update_status (p)
      struct Lisp_Process *p;
 {
-  union { int i; WAITTYPE wt; } u;
   eassert (p->raw_status_new);
-  u.i = p->raw_status;
-  p->status = status_convert (u.wt);
+  p->status = status_convert (p->raw_status);
   p->raw_status_new = 0;
 }
 
@@ -412,8 +411,7 @@ update_status (p)
     the list that we use internally.  */
 
 static Lisp_Object
-status_convert (w)
-     WAITTYPE w;
+status_convert (int w)
 {
   if (WIFSTOPPED (w))
     return Fcons (Qstop, Fcons (make_number (WSTOPSIG (w)), Qnil));
@@ -474,10 +472,21 @@ status_message (p)
       synchronize_system_messages_locale ();
       signame = strsignal (code);
       if (signame == 0)
-       signame = "unknown";
-      string = build_string (signame);
+       string = build_string ("unknown");
+      else
+       {
+         int c1, c2;
+
+         string = make_unibyte_string (signame, strlen (signame));
+         if (! NILP (Vlocale_coding_system))
+           string = (code_convert_string_norecord
+                     (string, Vlocale_coding_system, 0));
+         c1 = STRING_CHAR ((char *) SDATA (string));
+         c2 = DOWNCASE (c1);
+         if (c1 != c2)
+           Faset (string, make_number (0), make_number (c2));
+       }
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
-      SSET (string, 0, DOWNCASE (SREF (string, 0)));
       return concat2 (string, string2);
     }
   else if (EQ (symbol, Qexit))
@@ -533,14 +542,6 @@ allocate_pty ()
        PTY_OPEN;
 #else /* no PTY_OPEN */
        {
-# ifdef IRIS
-         /* Unusual IRIS code */
-         *ptyv = emacs_open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
-         if (fd < 0)
-           return -1;
-         if (fstat (fd, &stb) < 0)
-           return -1;
-# else /* not IRIS */
          { /* Some systems name their pseudoterminals so that there are gaps in
               the usual sequence - for example, on HP9000/S700 systems, there
               are no pseudoterminals with names ending in 'f'.  So we wait for
@@ -562,7 +563,6 @@ allocate_pty ()
 #  else
          fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0);
 #  endif
-# endif /* not IRIS */
        }
 #endif /* no PTY_OPEN */
 
@@ -573,16 +573,16 @@ allocate_pty ()
 #ifdef PTY_TTY_NAME_SPRINTF
            PTY_TTY_NAME_SPRINTF
 #else
-            sprintf (pty_name, "/dev/tty%c%x", c, i);
+           sprintf (pty_name, "/dev/tty%c%x", c, i);
 #endif /* no PTY_TTY_NAME_SPRINTF */
            if (access (pty_name, 6) != 0)
              {
                emacs_close (fd);
-# if !defined(IRIS) && !defined(__sgi)
+# ifndef __sgi
                continue;
 # else
                return -1;
-# endif /* IRIS */
+# endif /* __sgi */
              }
            setup_pty (fd);
            return fd;
@@ -612,6 +612,7 @@ make_process (name)
   p->raw_status_new = 0;
   p->status = Qrun;
   p->mark = Fmake_marker ();
+  p->kill_without_query = 0;
 
 #ifdef ADAPTIVE_READ_BUFFERING
   p->adaptive_read_buffering = 0;
@@ -784,11 +785,12 @@ nil, indicating the current buffer's process.  */)
   p = XPROCESS (process);
 
   p->raw_status_new = 0;
-  if (NETCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p))
     {
       p->status = Fcons (Qexit, Fcons (make_number (0), Qnil));
       p->tick = ++process_tick;
       status_notify (p);
+      redisplay_preserve_echo_area (13);
     }
   else if (p->infd >= 0)
     {
@@ -820,6 +822,7 @@ nil, indicating the current buffer's process.  */)
            = Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil));
          p->tick = ++process_tick;
          status_notify (p);
+         redisplay_preserve_echo_area (13);
        }
     }
   remove_process (process);
@@ -861,7 +864,7 @@ nil, indicating the current buffer's process.  */)
   status = p->status;
   if (CONSP (status))
     status = XCAR (status);
-  if (NETCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p))
     {
       if (EQ (status, Qexit))
        status = Qclosed;
@@ -919,7 +922,8 @@ DEFUN ("process-command", Fprocess_command, Sprocess_command, 1, 1, 0,
        doc: /* Return the command that was executed to start PROCESS.
 This is a list of strings, the first string being the program executed
 and the rest of the strings being the arguments given to it.
-For a non-child channel, this is nil.  */)
+For a network or serial process, this is nil (process is running) or t
+\(process is stopped).  */)
      (process)
      register Lisp_Object process;
 {
@@ -951,7 +955,7 @@ DEFUN ("set-process-buffer", Fset_process_buffer, Sset_process_buffer,
     CHECK_BUFFER (buffer);
   p = XPROCESS (process);
   p->buffer = buffer;
-  if (NETCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p))
     p->childp = Fplist_put (p->childp, QCbuffer, buffer);
   setup_process_coding_systems (process);
   return buffer;
@@ -1018,7 +1022,8 @@ The string argument is normally a multibyte string, except:
          FD_CLR (p->infd, &non_keyboard_wait_mask);
        }
       else if (EQ (p->filter, Qt)
-              && !EQ (p->command, Qt)) /* Network process not stopped. */
+              /* Network or serial process not stopped:  */
+              && !EQ (p->command, Qt))
        {
          FD_SET (p->infd, &input_wait_mask);
          FD_SET (p->infd, &non_keyboard_wait_mask);
@@ -1026,7 +1031,7 @@ The string argument is normally a multibyte string, except:
     }
 
   p->filter = filter;
-  if (NETCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p))
     p->childp = Fplist_put (p->childp, QCfilter, filter);
   setup_process_coding_systems (process);
   return filter;
@@ -1057,7 +1062,7 @@ It gets two arguments: the process, and a string describing the change.  */)
   p = XPROCESS (process);
 
   p->sentinel = sentinel;
-  if (NETCONN1_P (p))
+  if (NETCONN1_P (p) || SERIALCONN1_P (p))
     p->childp = Fplist_put (p->childp, QCsentinel, sentinel);
   return sentinel;
 }
@@ -1135,7 +1140,7 @@ DEFUN ("set-process-query-on-exit-flag",
        2, 2, 0,
        doc: /* Specify if query is needed for PROCESS when Emacs is exited.
 If the second argument FLAG is non-nil, Emacs will query the user before
-exiting if PROCESS is running.  */)
+exiting or killing a buffer if PROCESS is running.  */)
      (process, flag)
      register Lisp_Object process, flag;
 {
@@ -1162,11 +1167,13 @@ Lisp_Object Fprocess_datagram_address ();
 DEFUN ("process-contact", Fprocess_contact, Sprocess_contact,
        1, 2, 0,
        doc: /* Return the contact info of PROCESS; t for a real child.
-For a net connection, the value depends on the optional KEY arg.
-If KEY is nil, value is a cons cell of the form (HOST SERVICE),
-if KEY is t, the complete contact information for the connection is
-returned, else the specific value for the keyword KEY is returned.
-See `make-network-process' for a list of keywords.  */)
+For a network or serial connection, the value depends on the optional
+KEY arg.  If KEY is nil, value is a cons cell of the form (HOST
+SERVICE) for a network connection or (PORT SPEED) for a serial
+connection.  If KEY is t, the complete contact information for the
+connection is returned, else the specific value for the keyword KEY is
+returned.  See `make-network-process' or `make-serial-process' for a
+list of keywords.  */)
      (process, key)
      register Lisp_Object process, key;
 {
@@ -1182,11 +1189,14 @@ See `make-network-process' for a list of keywords.  */)
                          Fprocess_datagram_address (process));
 #endif
 
-  if (!NETCONN_P (process) || EQ (key, Qt))
+  if ((!NETCONN_P (process) && !SERIALCONN_P (process)) || EQ (key, Qt))
     return contact;
-  if (NILP (key))
+  if (NILP (key) && NETCONN_P (process))
     return Fcons (Fplist_get (contact, QChost),
                  Fcons (Fplist_get (contact, QCservice), Qnil));
+  if (NILP (key) && SERIALCONN_P (process))
+    return Fcons (Fplist_get (contact, QCport),
+                 Fcons (Fplist_get (contact, QCspeed), Qnil));
   return Fplist_get (contact, key);
 }
 
@@ -1226,6 +1236,19 @@ a socket connection.  */)
 }
 #endif
 
+DEFUN ("process-type", Fprocess_type, Sprocess_type, 1, 1, 0,
+       doc: /* Return the connection type of PROCESS.
+The value is either the symbol `real', `network', or `serial'.
+PROCESS may be a process, a buffer, the name of a process or buffer, or
+nil, indicating the current buffer's process.  */)
+     (process)
+     Lisp_Object process;
+{
+  Lisp_Object proc;
+  proc = get_process (process);
+  return XPROCESS (proc)->type;
+}
+
 #ifdef HAVE_SOCKETS
 DEFUN ("format-network-address", Fformat_network_address, Sformat_network_address,
        1, 2, 0,
@@ -1325,7 +1348,7 @@ list_processes_1 (query_only)
 
       proc = Fcdr (XCAR (tail));
       p = XPROCESS (proc);
-      if (NILP (p->childp))
+      if (NILP (p->type))
        continue;
       if (!NILP (query_only) && p->kill_without_query)
        continue;
@@ -1393,7 +1416,7 @@ list_processes_1 (query_only)
 
       proc = Fcdr (XCAR (tail));
       p = XPROCESS (proc);
-      if (NILP (p->childp))
+      if (NILP (p->type))
        continue;
       if (!NILP (query_only) && p->kill_without_query)
        continue;
@@ -1411,14 +1434,9 @@ list_processes_1 (query_only)
        {
          Lisp_Object tem;
          tem = Fcar (Fcdr (p->status));
-#ifdef VMS
-         if (XINT (tem) < NSIG)
-           write_string (sys_errlist [XINT (tem)], -1);
-         else
-#endif
-           Fprinc (symbol, Qnil);
+         Fprinc (symbol, Qnil);
        }
-      else if (NETCONN1_P (p))
+      else if (NETCONN1_P (p) || SERIALCONN1_P (p))
        {
          if (EQ (symbol, Qexit))
            write_string ("closed", -1);
@@ -1429,6 +1447,10 @@ list_processes_1 (query_only)
          else
            Fprinc (symbol, Qnil);
        }
+      else if (SERIALCONN1_P (p))
+       {
+         write_string ("running", -1);
+       }
       else
        Fprinc (symbol, Qnil);
 
@@ -1476,7 +1498,7 @@ list_processes_1 (query_only)
          insert_string (tembuf);
        }
       else if (NETCONN1_P (p))
-        {
+       {
          /* For a local socket, there is no host name,
             so display service instead.  */
          Lisp_Object host = Fplist_get (p->childp, QChost);
@@ -1492,13 +1514,31 @@ list_processes_1 (query_only)
                   (DATAGRAM_CHAN_P (p->infd) ? "datagram" : "stream"),
                   (STRINGP (host) ? (char *)SDATA (host) : "?"));
          insert_string (tembuf);
-        }
+       }
+      else if (SERIALCONN1_P (p))
+       {
+         Lisp_Object port = Fplist_get (p->childp, QCport);
+         Lisp_Object speed = Fplist_get (p->childp, QCspeed);
+         insert_string ("(serial port ");
+         if (STRINGP (port))
+           insert_string (SDATA (port));
+         else
+           insert_string ("?");
+         if (INTEGERP (speed))
+           {
+             sprintf (tembuf, " at %ld b/s", (long) XINT (speed));
+             insert_string (tembuf);
+           }
+         insert_string (")\n");
+       }
       else
        {
          tem = p->command;
          while (1)
            {
              tem1 = Fcar (tem);
+             if (NILP (tem1))
+               break;
              Finsert (1, &tem1);
              tem = Fcdr (tem);
              if (NILP (tem))
@@ -1509,7 +1549,10 @@ list_processes_1 (query_only)
        }
     }
   if (exited)
-    status_notify (NULL);
+    {
+      status_notify (NULL);
+      redisplay_preserve_echo_area (13);
+    }
   return Qnil;
 }
 
@@ -1548,8 +1591,9 @@ at end of BUFFER, unless you specify an output stream or filter
 function to handle the output.  BUFFER may also be nil, meaning that
 this process is not associated with any buffer.
 
-PROGRAM is the program file name.  It is searched for in PATH.
-Remaining arguments are strings to give program as arguments.
+PROGRAM is the program file name.  It is searched for in PATH.  If
+nil, just associate a pty with the buffer.  Remaining arguments are
+strings to give program as arguments.
 
 If you want to separate standard output from standard error, invoke
 the command through a shell and redirect one of them using the shell
@@ -1561,12 +1605,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
      register Lisp_Object *args;
 {
   Lisp_Object buffer, name, program, proc, current_dir, tem;
-#ifdef VMS
-  register unsigned char *new_argv;
-  int len;
-#else
   register unsigned char **new_argv;
-#endif
   register int i;
   int count = SPECPDL_INDEX ();
 
@@ -1608,7 +1647,8 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
 
   program = args[2];
 
-  CHECK_STRING (program);
+  if (!NILP (program))
+    CHECK_STRING (program);
 
   proc = make_process (name);
   /* If an error occurs and we can't start the process, we want to
@@ -1619,6 +1659,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
 
   XPROCESS (proc)->childp = Qt;
   XPROCESS (proc)->plist = Qnil;
+  XPROCESS (proc)->type = Qreal;
   XPROCESS (proc)->buffer = buffer;
   XPROCESS (proc)->sentinel = Qnil;
   XPROCESS (proc)->filter = Qnil;
@@ -1653,7 +1694,8 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
        args2[0] = Qstart_process;
        for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
        GCPRO2 (proc, current_dir);
-       coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
+       if (!NILP (program))
+         coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
        UNGCPRO;
        if (CONSP (coding_systems))
          val = XCAR (coding_systems);
@@ -1671,7 +1713,8 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
            args2[0] = Qstart_process;
            for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
            GCPRO2 (proc, current_dir);
-           coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
+           if (!NILP (program))
+             coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
            UNGCPRO;
          }
        if (CONSP (coding_systems))
@@ -1682,89 +1725,86 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS)  */)
     XPROCESS (proc)->encode_coding_system = val;
   }
 
-#ifdef VMS
-  /* Make a one member argv with all args concatenated
-     together separated by a blank.  */
-  len = SBYTES (program) + 2;
-  for (i = 3; i < nargs; i++)
-    {
-      tem = args[i];
-      CHECK_STRING (tem);
-      len += SBYTES (tem) + 1; /* count the blank */
-    }
-  new_argv = (unsigned char *) alloca (len);
-  strcpy (new_argv, SDATA (program));
-  for (i = 3; i < nargs; i++)
-    {
-      tem = args[i];
-      CHECK_STRING (tem);
-      strcat (new_argv, " ");
-      strcat (new_argv, SDATA (tem));
-    }
-  /* Need to add code here to check for program existence on VMS */
 
-#else /* not VMS */
-  new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
+  XPROCESS (proc)->decoding_buf = make_uninit_string (0);
+  XPROCESS (proc)->decoding_carryover = 0;
+  XPROCESS (proc)->encoding_buf = make_uninit_string (0);
 
-  /* If program file name is not absolute, search our path for it.
-     Put the name we will really use in TEM.  */
-  if (!IS_DIRECTORY_SEP (SREF (program, 0))
-      && !(SCHARS (program) > 1
-          && IS_DEVICE_SEP (SREF (program, 1))))
-    {
-      struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  XPROCESS (proc)->inherit_coding_system_flag
+    = !(NILP (buffer) || !inherit_process_coding_system);
 
-      tem = Qnil;
-      GCPRO4 (name, program, buffer, current_dir);
-      openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK));
-      UNGCPRO;
-      if (NILP (tem))
-       report_file_error ("Searching for program", Fcons (program, Qnil));
-      tem = Fexpand_file_name (tem, Qnil);
-    }
-  else
+  if (!NILP (program))
     {
-      if (!NILP (Ffile_directory_p (program)))
-       error ("Specified program for new process is a directory");
-      tem = program;
-    }
+      /* If program file name is not absolute, search our path for it.
+        Put the name we will really use in TEM.  */
+      if (!IS_DIRECTORY_SEP (SREF (program, 0))
+         && !(SCHARS (program) > 1
+              && IS_DEVICE_SEP (SREF (program, 1))))
+       {
+         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
+         tem = Qnil;
+         GCPRO4 (name, program, buffer, current_dir);
+         openp (Vexec_path, program, Vexec_suffixes, &tem, make_number (X_OK));
+         UNGCPRO;
+         if (NILP (tem))
+           report_file_error ("Searching for program", Fcons (program, Qnil));
+         tem = Fexpand_file_name (tem, Qnil);
+       }
+      else
+       {
+         if (!NILP (Ffile_directory_p (program)))
+           error ("Specified program for new process is a directory");
+         tem = program;
+       }
 
-  /* If program file name starts with /: for quoting a magic name,
-     discard that.  */
-  if (SBYTES (tem) > 2 && SREF (tem, 0) == '/'
-      && SREF (tem, 1) == ':')
-    tem = Fsubstring (tem, make_number (2), Qnil);
+      /* If program file name starts with /: for quoting a magic name,
+        discard that.  */
+      if (SBYTES (tem) > 2 && SREF (tem, 0) == '/'
+         && SREF (tem, 1) == ':')
+       tem = Fsubstring (tem, make_number (2), Qnil);
 
-  /* Encode the file name and put it in NEW_ARGV.
-     That's where the child will use it to execute the program.  */
-  tem = ENCODE_FILE (tem);
-  new_argv[0] = SDATA (tem);
+      {
+       struct gcpro gcpro1;
+       GCPRO1 (tem);
 
-  /* Here we encode arguments by the coding system used for sending
-     data to the process.  We don't support using different coding
-     systems for encoding arguments and for encoding data sent to the
-     process.  */
+       /* Encode the file name and put it in NEW_ARGV.
+          That's where the child will use it to execute the program.  */
+       tem = Fcons (ENCODE_FILE (tem), Qnil);
 
-  for (i = 3; i < nargs; i++)
-    {
-      tem = args[i];
-      CHECK_STRING (tem);
-      if (STRING_MULTIBYTE (tem))
-       tem = (code_convert_string_norecord
-              (tem, XPROCESS (proc)->encode_coding_system, 1));
-      new_argv[i - 2] = SDATA (tem);
-    }
-  new_argv[i - 2] = 0;
-#endif /* not VMS */
+       /* Here we encode arguments by the coding system used for sending
+          data to the process.  We don't support using different coding
+          systems for encoding arguments and for encoding data sent to the
+          process.  */
 
-  XPROCESS (proc)->decoding_buf = make_uninit_string (0);
-  XPROCESS (proc)->decoding_carryover = 0;
-  XPROCESS (proc)->encoding_buf = make_uninit_string (0);
+       for (i = 3; i < nargs; i++)
+         {
+           tem = Fcons (args[i], tem);
+           CHECK_STRING (XCAR (tem));
+           if (STRING_MULTIBYTE (XCAR (tem)))
+             XSETCAR (tem,
+                      code_convert_string_norecord
+                      (XCAR (tem), XPROCESS (proc)->encode_coding_system, 1));
+         }
 
-  XPROCESS (proc)->inherit_coding_system_flag
-    = !(NILP (buffer) || !inherit_process_coding_system);
+       UNGCPRO;
+      }
+
+      /* Now that everything is encoded we can collect the strings into
+        NEW_ARGV.  */
+      new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
+      new_argv[nargs - 2] = 0;
 
-  create_process (proc, (char **) new_argv, current_dir);
+      for (i = nargs - 3; i >= 0; i--)
+       {
+         new_argv[i] = SDATA (XCAR (tem));
+         tem = XCDR (tem);
+       }
+
+      create_process (proc, (char **) new_argv, current_dir);
+    }
+  else
+    create_pty (proc);
 
   return unbind_to (count, proc);
 }
@@ -1781,7 +1821,7 @@ start_process_unwind (proc)
     abort ();
 
   /* Was PROC started successfully?  */
-  if (XPROCESS (proc)->pid <= 0)
+  if (XPROCESS (proc)->pid == -1)
     remove_process (proc);
 
   return Qnil;
@@ -1814,7 +1854,6 @@ create_process_sigchld ()
 #endif
 #endif
 
-#ifndef VMS /* VMS version of this function is in vmsproc.c.  */
 void
 create_process (process, new_argv, current_dir)
      Lisp_Object process;
@@ -1824,6 +1863,9 @@ create_process (process, new_argv, current_dir)
   int inchannel, outchannel;
   pid_t pid;
   int sv[2];
+#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+  int wait_child_setup[2];
+#endif
 #ifdef POSIX_SIGNALS
   sigset_t procmask;
   sigset_t blocked;
@@ -1832,13 +1874,7 @@ create_process (process, new_argv, current_dir)
 #ifdef AIX
   struct sigaction sighup_action;
 #endif
-#else /* !POSIX_SIGNALS */
-#if 0
-#ifdef SIGCHLD
-  SIGTYPE (*sigchld)();
-#endif
-#endif /* 0 */
-#endif /* !POSIX_SIGNALS */
+#endif /* POSIX_SIGNALS */
   /* Use volatile to protect variables from being clobbered by longjmp.  */
   volatile int forkin, forkout;
   volatile int pty_flag = 0;
@@ -1866,12 +1902,6 @@ create_process (process, new_argv, current_dir)
 #endif
       if (forkin < 0)
        report_file_error ("Opening pty", Qnil);
-#if defined (DONT_REOPEN_PTY)
-      /* In the case that vfork is defined as fork, the parent process
-        (Emacs) may send some data before the child process completes
-        tty options setup.  So we setup tty before forking.  */
-      child_setup_tty (forkout);
-#endif /* DONT_REOPEN_PTY */
 #else
       forkin = forkout = -1;
 #endif /* not USG, or USG_SUBTTY_WORKS */
@@ -1897,6 +1927,25 @@ create_process (process, new_argv, current_dir)
       forkin = sv[0];
     }
 
+#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+    {
+      int tem;
+
+      tem = pipe (wait_child_setup);
+      if (tem < 0)
+       report_file_error ("Creating pipe", Qnil);
+      tem = fcntl (wait_child_setup[1], F_GETFD, 0);
+      if (tem >= 0)
+       tem = fcntl (wait_child_setup[1], F_SETFD, tem | FD_CLOEXEC);
+      if (tem < 0)
+       {
+         emacs_close (wait_child_setup[0]);
+         emacs_close (wait_child_setup[1]);
+         report_file_error ("Setting file descriptor flags", Qnil);
+       }
+    }
+#endif
+
 #if 0
   /* Replaced by close_process_descs */
   set_exclusive_use (inchannel);
@@ -1949,18 +1998,9 @@ create_process (process, new_argv, current_dir)
   sigprocmask (SIG_BLOCK, &blocked, &procmask);
 #else /* !POSIX_SIGNALS */
 #ifdef SIGCHLD
-#ifdef BSD4_1
-  sighold (SIGCHLD);
-#else /* not BSD4_1 */
-#if defined (BSD_SYSTEM) || defined (HPUX)
+#if defined (BSD_SYSTEM)
   sigsetmask (sigmask (SIGCHLD));
-#else /* ordinary USG */
-#if 0
-  sigchld_deferred = 0;
-  sigchld = signal (SIGCHLD, create_process_sigchld);
-#endif
-#endif /* ordinary USG */
-#endif /* not BSD4_1 */
+#endif /* BSD_SYSTEM */
 #endif /* SIGCHLD */
 #endif /* !POSIX_SIGNALS */
 
@@ -2077,9 +2117,6 @@ create_process (process, new_argv, current_dir)
           This makes the pty the controlling terminal of the subprocess.  */
        if (pty_flag)
          {
-#ifdef SET_CHILD_PTY_PGRP
-           int pgrp = getpid ();
-#endif
 
            /* I wonder if emacs_close (emacs_open (pty_name, ...))
               would work?  */
@@ -2095,10 +2132,6 @@ create_process (process, new_argv, current_dir)
                _exit (1);
              }
 
-#ifdef SET_CHILD_PTY_PGRP
-           ioctl (xforkin, TIOCSPGRP, &pgrp);
-           ioctl (xforkout, TIOCSPGRP, &pgrp);
-#endif
          }
 #endif /* not DONT_REOPEN_PTY */
 
@@ -2124,28 +2157,21 @@ create_process (process, new_argv, current_dir)
        sigprocmask (SIG_SETMASK, &procmask, 0);
 #else /* !POSIX_SIGNALS */
 #ifdef SIGCHLD
-#ifdef BSD4_1
-       sigrelse (SIGCHLD);
-#else /* not BSD4_1 */
-#if defined (BSD_SYSTEM) || defined (HPUX)
+#if defined (BSD_SYSTEM)
        sigsetmask (SIGEMPTYMASK);
-#else /* ordinary USG */
-#if 0
-       signal (SIGCHLD, sigchld);
-#endif
-#endif /* ordinary USG */
-#endif /* not BSD4_1 */
+#endif /* BSD_SYSTEM */
 #endif /* SIGCHLD */
 #endif /* !POSIX_SIGNALS */
 
-#if !defined (DONT_REOPEN_PTY)
        if (pty_flag)
          child_setup_tty (xforkout);
-#endif /* not DONT_REOPEN_PTY */
 #ifdef WINDOWSNT
        pid = child_setup (xforkin, xforkout, xforkout,
                           new_argv, 1, current_dir);
 #else  /* not WINDOWSNT */
+#ifdef FD_CLOEXEC
+       emacs_close (wait_child_setup[0]);
+#endif
        child_setup (xforkin, xforkout, xforkout,
                     new_argv, 1, current_dir);
 #endif /* not WINDOWSNT */
@@ -2199,6 +2225,20 @@ create_process (process, new_argv, current_dir)
       else
 #endif
        XPROCESS (process)->tty_name = Qnil;
+
+#if !defined (WINDOWSNT) && defined (FD_CLOEXEC)
+      /* Wait for child_setup to complete in case that vfork is
+        actually defined as fork.  The descriptor wait_child_setup[1]
+        of a pipe is closed at the child side either by close-on-exec
+        on successful execvp or the _exit call in child_setup.  */
+      {
+       char dummy;
+
+       emacs_close (wait_child_setup[1]);
+       emacs_read (wait_child_setup[0], &dummy, 1);
+       emacs_close (wait_child_setup[0]);
+      }
+#endif
     }
 
   /* Restore the signal state whether vfork succeeded or not.
@@ -2216,21 +2256,9 @@ create_process (process, new_argv, current_dir)
   sigprocmask (SIG_SETMASK, &procmask, 0);
 #else /* !POSIX_SIGNALS */
 #ifdef SIGCHLD
-#ifdef BSD4_1
-  sigrelse (SIGCHLD);
-#else /* not BSD4_1 */
-#if defined (BSD_SYSTEM) || defined (HPUX)
+#if defined (BSD_SYSTEM)
   sigsetmask (SIGEMPTYMASK);
-#else /* ordinary USG */
-#if 0
-  signal (SIGCHLD, sigchld);
-  /* Now really handle any of these signals
-     that came in during this function.  */
-  if (sigchld_deferred)
-    kill (getpid (), SIGCHLD);
-#endif
-#endif /* ordinary USG */
-#endif /* not BSD4_1 */
+#endif /* BSD_SYSTEM */
 #endif /* SIGCHLD */
 #endif /* !POSIX_SIGNALS */
 
@@ -2238,7 +2266,88 @@ create_process (process, new_argv, current_dir)
   if (pid < 0)
     report_file_error ("Doing vfork", Qnil);
 }
-#endif /* not VMS */
+
+void
+create_pty (process)
+     Lisp_Object process;
+{
+  int inchannel, outchannel;
+
+  /* Use volatile to protect variables from being clobbered by longjmp.  */
+  volatile int forkin, forkout;
+  volatile int pty_flag = 0;
+
+  inchannel = outchannel = -1;
+
+#ifdef HAVE_PTYS
+  if (!NILP (Vprocess_connection_type))
+    outchannel = inchannel = allocate_pty ();
+
+  if (inchannel >= 0)
+    {
+#if ! defined (USG) || defined (USG_SUBTTY_WORKS)
+      /* On most USG systems it does not work to open the pty's tty here,
+        then close it and reopen it in the child.  */
+#ifdef O_NOCTTY
+      /* Don't let this terminal become our controlling terminal
+        (in case we don't have one).  */
+      forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
+#else
+      forkout = forkin = emacs_open (pty_name, O_RDWR, 0);
+#endif
+      if (forkin < 0)
+       report_file_error ("Opening pty", Qnil);
+#if defined (DONT_REOPEN_PTY)
+      /* In the case that vfork is defined as fork, the parent process
+        (Emacs) may send some data before the child process completes
+        tty options setup.  So we setup tty before forking.  */
+      child_setup_tty (forkout);
+#endif /* DONT_REOPEN_PTY */
+#else
+      forkin = forkout = -1;
+#endif /* not USG, or USG_SUBTTY_WORKS */
+      pty_flag = 1;
+    }
+#endif /* HAVE_PTYS */
+
+#ifdef O_NONBLOCK
+  fcntl (inchannel, F_SETFL, O_NONBLOCK);
+  fcntl (outchannel, F_SETFL, O_NONBLOCK);
+#else
+#ifdef O_NDELAY
+  fcntl (inchannel, F_SETFL, O_NDELAY);
+  fcntl (outchannel, F_SETFL, O_NDELAY);
+#endif
+#endif
+
+  /* Record this as an active process, with its channels.
+     As a result, child_setup will close Emacs's side of the pipes.  */
+  chan_process[inchannel] = process;
+  XPROCESS (process)->infd = inchannel;
+  XPROCESS (process)->outfd = outchannel;
+
+  /* Previously we recorded the tty descriptor used in the subprocess.
+     It was only used for getting the foreground tty process, so now
+     we just reopen the device (see emacs_get_tty_pgrp) as this is
+     more portable (see USG_SUBTTY_WORKS above).  */
+
+  XPROCESS (process)->pty_flag = pty_flag;
+  XPROCESS (process)->status = Qrun;
+  setup_process_coding_systems (process);
+
+  FD_SET (inchannel, &input_wait_mask);
+  FD_SET (inchannel, &non_keyboard_wait_mask);
+  if (inchannel > max_process_desc)
+    max_process_desc = inchannel;
+
+  XPROCESS (process)->pid = -2;
+#ifdef HAVE_PTYS
+  if (pty_flag)
+    XPROCESS (process)->tty_name = build_string (pty_name);
+  else
+#endif
+    XPROCESS (process)->tty_name = Qnil;
+}
 
 \f
 #ifdef HAVE_SOCKETS
@@ -2256,6 +2365,12 @@ conv_sockaddr_to_lisp (sa, len)
   unsigned char *cp;
   register struct Lisp_Vector *p;
 
+  /* Workaround for a bug in getsockname on BSD: Names bound to
+     sockets in the UNIX domain are inaccessible; getsockname returns
+     a zero length name.  */
+  if (len < OFFSETOF (struct sockaddr, sa_family) + sizeof (sa->sa_family))
+    return empty_unibyte_string;
+
   switch (sa->sa_family)
     {
     case AF_INET:
@@ -2265,14 +2380,14 @@ conv_sockaddr_to_lisp (sa, len)
        address = Fmake_vector (make_number (len), Qnil);
        p = XVECTOR (address);
        p->contents[--len] = make_number (ntohs (sin->sin_port));
-       cp = (unsigned char *)&sin->sin_addr;
+       cp = (unsigned char *) &sin->sin_addr;
        break;
       }
 #ifdef AF_INET6
     case AF_INET6:
       {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sa;
-       uint16_t *ip6 = (uint16_t *)&sin6->sin6_addr;
+       uint16_t *ip6 = (uint16_t *) &sin6->sin6_addr;
        len = sizeof (sin6->sin6_addr)/2 + 1;
        address = Fmake_vector (make_number (len), Qnil);
        p = XVECTOR (address);
@@ -2293,11 +2408,11 @@ conv_sockaddr_to_lisp (sa, len)
       }
 #endif
     default:
-      len -= sizeof (sa->sa_family);
+      len -= OFFSETOF (struct sockaddr, sa_family) + sizeof (sa->sa_family);
       address = Fcons (make_number (sa->sa_family),
                       Fmake_vector (make_number (len), Qnil));
       p = XVECTOR (XCDR (address));
-      cp = (unsigned char *) sa + sizeof (sa->sa_family);
+      cp = (unsigned char *) &sa->sa_family + sizeof (sa->sa_family);
       break;
     }
 
@@ -2472,7 +2587,7 @@ Returns nil upon error setting address, ADDRESS otherwise.  */)
 #endif
 \f
 
-static struct socket_options {
+static const struct socket_options {
   /* The name of this option.  Should be lowercase version of option
      name without SO_ prefix. */
   char *name;
@@ -2523,7 +2638,7 @@ set_socket_option (s, opt, val)
      Lisp_Object opt, val;
 {
   char *name;
-  struct socket_options *sopt;
+  const struct socket_options *sopt;
   int ret = 0;
 
   CHECK_SYMBOL (opt);
@@ -2643,18 +2758,307 @@ OPTION is not a supported option, return nil instead; otherwise return t.  */)
 }
 
 \f
-/* A version of request_sigio suitable for a record_unwind_protect.  */
+#ifdef HAVE_SERIAL
+DEFUN ("serial-process-configure",
+       Fserial_process_configure,
+       Sserial_process_configure,
+       0, MANY, 0,
+       doc: /* Configure speed, bytesize, etc. of a serial process.
 
-#ifdef __ultrix__
-static Lisp_Object
-unwind_request_sigio (dummy)
-     Lisp_Object dummy;
+Arguments are specified as keyword/argument pairs.  Attributes that
+are not given are re-initialized from the process's current
+configuration (available via the function `process-contact') or set to
+reasonable default values.  The following arguments are defined:
+
+:process PROCESS
+:name NAME
+:buffer BUFFER
+:port PORT
+-- Any of these arguments can be given to identify the process that is
+to be configured.  If none of these arguments is given, the current
+buffer's process is used.
+
+:speed SPEED -- SPEED is the speed of the serial port in bits per
+second, also called baud rate.  Any value can be given for SPEED, but
+most serial ports work only at a few defined values between 1200 and
+115200, with 9600 being the most common value.  If SPEED is nil, the
+serial port is not configured any further, i.e., all other arguments
+are ignored.  This may be useful for special serial ports such as
+Bluetooth-to-serial converters which can only be configured through AT
+commands.  A value of nil for SPEED can be used only when passed
+through `make-serial-process' or `serial-term'.
+
+:bytesize BYTESIZE -- BYTESIZE is the number of bits per byte, which
+can be 7 or 8.  If BYTESIZE is not given or nil, a value of 8 is used.
+
+:parity PARITY -- PARITY can be nil (don't use parity), the symbol
+`odd' (use odd parity), or the symbol `even' (use even parity).  If
+PARITY is not given, no parity is used.
+
+:stopbits STOPBITS -- STOPBITS is the number of stopbits used to
+terminate a byte transmission.  STOPBITS can be 1 or 2.  If STOPBITS
+is not given or nil, 1 stopbit is used.
+
+:flowcontrol FLOWCONTROL -- FLOWCONTROL determines the type of
+flowcontrol to be used, which is either nil (don't use flowcontrol),
+the symbol `hw' (use RTS/CTS hardware flowcontrol), or the symbol `sw'
+\(use XON/XOFF software flowcontrol).  If FLOWCONTROL is not given, no
+flowcontrol is used.
+
+`serial-process-configure' is called by `make-serial-process' for the
+initial configuration of the serial port.
+
+Examples:
+
+\(serial-process-configure :process "/dev/ttyS0" :speed 1200)
+
+\(serial-process-configure
+    :buffer "COM1" :stopbits 1 :parity 'odd :flowcontrol 'hw)
+
+\(serial-process-configure :port "\\\\.\\COM13" :bytesize 7)
+
+usage: (serial-process-configure &rest ARGS)  */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
 {
-  if (interrupt_input)
-    request_sigio ();
+  struct Lisp_Process *p;
+  Lisp_Object contact = Qnil;
+  Lisp_Object proc = Qnil;
+  struct gcpro gcpro1;
+
+  contact = Flist (nargs, args);
+  GCPRO1 (contact);
+
+  proc = Fplist_get (contact, QCprocess);
+  if (NILP (proc))
+    proc = Fplist_get (contact, QCname);
+  if (NILP (proc))
+    proc = Fplist_get (contact, QCbuffer);
+  if (NILP (proc))
+    proc = Fplist_get (contact, QCport);
+  proc = get_process (proc);
+  p = XPROCESS (proc);
+  if (!EQ (p->type, Qserial))
+    error ("Not a serial process");
+
+  if (NILP (Fplist_get (p->childp, QCspeed)))
+    {
+      UNGCPRO;
+      return Qnil;
+    }
+
+  serial_configure (p, contact);
+
+  UNGCPRO;
   return Qnil;
 }
-#endif
+
+/* Used by make-serial-process to recover from errors.  */
+Lisp_Object make_serial_process_unwind (Lisp_Object proc)
+{
+  if (!PROCESSP (proc))
+    abort ();
+  remove_process (proc);
+  return Qnil;
+}
+
+DEFUN ("make-serial-process", Fmake_serial_process, Smake_serial_process,
+       0, MANY, 0,
+       doc: /* Create and return a serial port process.
+
+In Emacs, serial port connections are represented by process objects,
+so input and output work as for subprocesses, and `delete-process'
+closes a serial port connection.  However, a serial process has no
+process id, it cannot be signaled, and the status codes are different
+from normal processes.
+
+`make-serial-process' creates a process and a buffer, on which you
+probably want to use `process-send-string'.  Try \\[serial-term] for
+an interactive terminal.  See below for examples.
+
+Arguments are specified as keyword/argument pairs.  The following
+arguments are defined:
+
+:port PORT -- (mandatory) PORT is the path or name of the serial port.
+For example, this could be "/dev/ttyS0" on Unix.  On Windows, this
+could be "COM1", or "\\\\.\\COM10" for ports higher than COM9 (double
+the backslashes in strings).
+
+:speed SPEED -- (mandatory) is handled by `serial-process-configure',
+which is called by `make-serial-process'.
+
+:name NAME -- NAME is the name of the process.  If NAME is not given,
+the value of PORT is used.
+
+:buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate
+with the process.  Process output goes at the end of that buffer,
+unless you specify an output stream or filter function to handle the
+output.  If BUFFER is not given, the value of NAME is used.
+
+:coding CODING -- If CODING is a symbol, it specifies the coding
+system used for both reading and writing for this process.  If CODING
+is a cons (DECODING . ENCODING), DECODING is used for reading, and
+ENCODING is used for writing.
+
+:noquery BOOL -- When exiting Emacs, query the user if BOOL is nil and
+the process is running.  If BOOL is not given, query before exiting.
+
+:stop BOOL -- Start process in the `stopped' state if BOOL is non-nil.
+In the stopped state, a serial process does not accept incoming data,
+but you can send outgoing data.  The stopped state is cleared by
+`continue-process' and set by `stop-process'.
+
+:filter FILTER -- Install FILTER as the process filter.
+
+:sentinel SENTINEL -- Install SENTINEL as the process sentinel.
+
+:plist PLIST -- Install PLIST as the initial plist of the process.
+
+:speed
+:bytesize
+:parity
+:stopbits
+:flowcontrol
+-- These arguments are handled by `serial-process-configure', which is
+called by `make-serial-process'.
+
+The original argument list, possibly modified by later configuration,
+is available via the function `process-contact'.
+
+Examples:
+
+\(make-serial-process :port "/dev/ttyS0" :speed 9600)
+
+\(make-serial-process :port "COM1" :speed 115200 :stopbits 2)
+
+\(make-serial-process :port "\\\\.\\COM13" :speed 1200 :bytesize 7 :parity 'odd)
+
+\(make-serial-process :port "/dev/tty.BlueConsole-SPP-1" :speed nil)
+
+usage:  (make-serial-process &rest ARGS)  */)
+     (nargs, args)
+     int nargs;
+     Lisp_Object *args;
+{
+  int fd = -1;
+  Lisp_Object proc, contact, port;
+  struct Lisp_Process *p;
+  struct gcpro gcpro1;
+  Lisp_Object name, buffer;
+  Lisp_Object tem, val;
+  int specpdl_count = -1;
+
+  if (nargs == 0)
+    return Qnil;
+
+  contact = Flist (nargs, args);
+  GCPRO1 (contact);
+
+  port = Fplist_get (contact, QCport);
+  if (NILP (port))
+    error ("No port specified");
+  CHECK_STRING (port);
+
+  if (NILP (Fplist_member (contact, QCspeed)))
+    error (":speed not specified");
+  if (!NILP (Fplist_get (contact, QCspeed)))
+    CHECK_NUMBER (Fplist_get (contact, QCspeed));
+
+  name = Fplist_get (contact, QCname);
+  if (NILP (name))
+    name = port;
+  CHECK_STRING (name);
+  proc = make_process (name);
+  specpdl_count = SPECPDL_INDEX ();
+  record_unwind_protect (make_serial_process_unwind, proc);
+  p = XPROCESS (proc);
+
+  fd = serial_open ((char*) SDATA (port));
+  p->infd = fd;
+  p->outfd = fd;
+  if (fd > max_process_desc)
+    max_process_desc = fd;
+  chan_process[fd] = proc;
+
+  buffer = Fplist_get (contact, QCbuffer);
+  if (NILP (buffer))
+    buffer = name;
+  buffer = Fget_buffer_create (buffer);
+  p->buffer = buffer;
+
+  p->childp = contact;
+  p->plist = Fcopy_sequence (Fplist_get (contact, QCplist));
+  p->type = Qserial;
+  p->sentinel = Fplist_get (contact, QCsentinel);
+  p->filter = Fplist_get (contact, QCfilter);
+  p->log = Qnil;
+  if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
+    p->kill_without_query = 1;
+  if (tem = Fplist_get (contact, QCstop), !NILP (tem))
+    p->command = Qt;
+  p->pty_flag = 0;
+
+  if (!EQ (p->command, Qt))
+    {
+      FD_SET (fd, &input_wait_mask);
+      FD_SET (fd, &non_keyboard_wait_mask);
+    }
+
+  if (BUFFERP (buffer))
+    {
+      set_marker_both (p->mark, buffer,
+                      BUF_ZV (XBUFFER (buffer)),
+                      BUF_ZV_BYTE (XBUFFER (buffer)));
+    }
+
+  tem = Fplist_member (contact, QCcoding);
+  if (!NILP (tem) && (!CONSP (tem) || !CONSP (XCDR (tem))))
+    tem = Qnil;
+
+  val = Qnil;
+  if (!NILP (tem))
+    {
+      val = XCAR (XCDR (tem));
+      if (CONSP (val))
+       val = XCAR (val);
+    }
+  else if (!NILP (Vcoding_system_for_read))
+    val = Vcoding_system_for_read;
+  else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters))
+          || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters)))
+    val = Qnil;
+  p->decode_coding_system = val;
+
+  val = Qnil;
+  if (!NILP (tem))
+    {
+      val = XCAR (XCDR (tem));
+      if (CONSP (val))
+       val = XCDR (val);
+    }
+  else if (!NILP (Vcoding_system_for_write))
+    val = Vcoding_system_for_write;
+  else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters))
+          || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters)))
+    val = Qnil;
+  p->encode_coding_system = val;
+
+  setup_process_coding_systems (proc);
+  p->decoding_buf = make_uninit_string (0);
+  p->decoding_carryover = 0;
+  p->encoding_buf = make_uninit_string (0);
+  p->inherit_coding_system_flag
+    = !(!NILP (tem) || NILP (buffer) || !inherit_process_coding_system);
+
+  Fserial_process_configure(nargs, args);
+
+  specpdl_ptr = specpdl + specpdl_count;
+
+  UNGCPRO;
+  return proc;
+}
+#endif /* HAVE_SERIAL  */
 
 /* Create a network stream/datagram client/server process.  Treated
    exactly like a normal process when reading and writing.  Primary
@@ -2696,7 +3100,8 @@ compiled with getaddrinfo, a port number can also be specified as a
 string, e.g. "80", as well as an integer.  This is not portable.)
 
 :type TYPE -- TYPE is the type of connection.  The default (nil) is a
-stream type connection, `datagram' creates a datagram type connection.
+stream type connection, `datagram' creates a datagram type connection,
+`seqpacket' creates a reliable datagram connection.
 
 :family FAMILY -- FAMILY is the address (and protocol) family for the
 service specified by HOST and SERVICE.  The default (nil) is to use
@@ -2874,6 +3279,10 @@ usage: (make-network-process &rest ARGS)  */)
 #ifdef DATAGRAM_SOCKETS
   else if (EQ (tem, Qdatagram))
     socktype = SOCK_DGRAM;
+#endif
+#ifdef HAVE_SEQPACKET
+  else if (EQ (tem, Qseqpacket))
+    socktype = SOCK_SEQPACKET;
 #endif
   else
     error ("Unsupported connection type");
@@ -2884,7 +3293,7 @@ usage: (make-network-process &rest ARGS)  */)
     {
       /* Don't support network sockets when non-blocking mode is
         not available, since a blocked Emacs is not useful.  */
-#if defined(TERM) || (!defined(O_NONBLOCK) && !defined(O_NDELAY))
+#if !defined(O_NONBLOCK) && !defined(O_NDELAY)
       error ("Network servers not supported");
 #else
       is_server = 1;
@@ -2897,7 +3306,7 @@ usage: (make-network-process &rest ARGS)  */)
   QCaddress = is_server ? QClocal : QCremote;
 
   /* :nowait BOOL */
-  if (!is_server && socktype == SOCK_STREAM
+  if (!is_server && socktype != SOCK_DGRAM
       && (tem = Fplist_get (contact, QCnowait), !NILP (tem)))
     {
 #ifndef NON_BLOCKING_CONNECT
@@ -2914,32 +3323,6 @@ usage: (make-network-process &rest ARGS)  */)
 
   CHECK_STRING (name);
 
-#ifdef TERM
-  /* Let's handle TERM before things get complicated ...   */
-  host = Fplist_get (contact, QChost);
-  CHECK_STRING (host);
-
-  service = Fplist_get (contact, QCservice);
-  if (INTEGERP (service))
-    port = htons ((unsigned short) XINT (service));
-  else
-    {
-      struct servent *svc_info;
-      CHECK_STRING (service);
-      svc_info = getservbyname (SDATA (service), "tcp");
-      if (svc_info == 0)
-       error ("Unknown service: %s", SDATA (service));
-      port = svc_info->s_port;
-    }
-
-  s = connect_server (0);
-  if (s < 0)
-    report_file_error ("error creating socket", Fcons (name, Qnil));
-  send_command (s, C_PORT, 0, "%s:%d", SDATA (host), ntohs (port));
-  send_command (s, C_DUMB, 1, 0);
-
-#else  /* not TERM */
-
   /* Initialize addrinfo structure in case we don't use getaddrinfo.  */
   ai.ai_socktype = socktype;
   ai.ai_protocol = 0;
@@ -3018,7 +3401,7 @@ usage: (make-network-process &rest ARGS)  */)
      Some kernels have a bug which causes retrying connect to fail
      after a connect.  Polling can interfere with gethostbyname too.  */
 #ifdef POLL_FOR_INPUT
-  if (socktype == SOCK_STREAM)
+  if (socktype != SOCK_DGRAM)
     {
       record_unwind_protect (unwind_stop_other_atimers, Qnil);
       bind_polling_period (10);
@@ -3063,7 +3446,7 @@ usage: (make-network-process &rest ARGS)  */)
 #ifdef HAVE_GAI_STRERROR
        error ("%s/%s %s", SDATA (host), portstring, gai_strerror(ret));
 #else
-        error ("%s/%s getaddrinfo error %d", SDATA (host), portstring, ret);
+       error ("%s/%s getaddrinfo error %d", SDATA (host), portstring, ret);
 #endif
       immediate_quit = 0;
 
@@ -3139,28 +3522,6 @@ usage: (make-network-process &rest ARGS)  */)
 
  open_socket:
 
-#ifdef __ultrix__
-  /* Previously this was compiled unconditionally, but that seems
-     unnecessary on modern systems, and `unrequest_sigio' was a noop
-     under X anyway. --lorentey */
-  /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
-     when connect is interrupted.  So let's not let it get interrupted.
-     Note we do not turn off polling, because polling is only used
-     when not interrupt_input, and thus not normally used on the systems
-     which have this bug.  On systems which use polling, there's no way
-     to quit if polling is turned off.  */
-  if (interrupt_input
-      && !is_server && socktype == SOCK_STREAM)
-    {
-      /* Comment from KFS: The original open-network-stream code
-        didn't unwind protect this, but it seems like the proper
-        thing to do.  In any case, I don't see how it could harm to
-        do this -- and it makes cleanup (using unbind_to) easier.  */
-      record_unwind_protect (unwind_request_sigio, Qnil);
-      unrequest_sigio ();
-    }
-#endif
-
   /* Do this in case we never enter the for-loop below.  */
   count1 = SPECPDL_INDEX ();
   s = -1;
@@ -3206,7 +3567,7 @@ usage: (make-network-process &rest ARGS)  */)
 
       /* Parse network options in the arg list.
         We simply ignore anything which isn't a known option (including other keywords).
-         An error is signalled if setting a known option fails.  */
+        An error is signaled if setting a known option fails.  */
       for (optn = optbits = 0; optn < nargs-1; optn += 2)
        optbits |= set_socket_option (s, args[optn], args[optn+1]);
 
@@ -3243,7 +3604,7 @@ usage: (make-network-process &rest ARGS)  */)
            }
 #endif
 
-         if (socktype == SOCK_STREAM && listen (s, backlog))
+         if (socktype != SOCK_DGRAM && listen (s, backlog))
            report_file_error ("Cannot listen on server socket", Qnil);
 
          break;
@@ -3252,23 +3613,9 @@ usage: (make-network-process &rest ARGS)  */)
       immediate_quit = 1;
       QUIT;
 
-      /* This turns off all alarm-based interrupts; the
-        bind_polling_period call above doesn't always turn all the
-        short-interval ones off, especially if interrupt_input is
-        set.
-
-        It'd be nice to be able to control the connect timeout
-        though.  Would non-blocking connect calls be portable?
-
-        This used to be conditioned by HAVE_GETADDRINFO.  Why?  */
-
-      turn_on_atimers (0);
-
       ret = connect (s, lres->ai_addr, lres->ai_addrlen);
       xerrno = errno;
 
-      turn_on_atimers (1);
-
       if (ret == 0 || xerrno == EISCONN)
        {
          /* The unwind-protect will be discarded afterwards.
@@ -3288,6 +3635,40 @@ usage: (make-network-process &rest ARGS)  */)
 #endif
 #endif
 
+#ifndef WINDOWSNT
+      if (xerrno == EINTR)
+       {
+         /* Unlike most other syscalls connect() cannot be called
+            again.  (That would return EALREADY.)  The proper way to
+            wait for completion is select(). */
+         int sc, len;
+         SELECT_TYPE fdset;
+       retry_select:
+         FD_ZERO (&fdset);
+         FD_SET (s, &fdset);
+         QUIT;
+         sc = select (s + 1, (SELECT_TYPE *)0, &fdset, (SELECT_TYPE *)0,
+                      (EMACS_TIME *)0);
+         if (sc == -1)
+           {
+             if (errno == EINTR)
+               goto retry_select;
+             else
+               report_file_error ("select failed", Qnil);
+           }
+         eassert (sc > 0);
+
+         len = sizeof xerrno;
+         eassert (FD_ISSET (s, &fdset));
+         if (getsockopt (s, SOL_SOCKET, SO_ERROR, &xerrno, &len) == -1)
+           report_file_error ("getsockopt failed", Qnil);
+         if (xerrno)
+           errno = xerrno, report_file_error ("error during connect", Qnil);
+         else
+           break;
+       }
+#endif /* !WINDOWSNT */
+
       immediate_quit = 0;
 
       /* Discard the unwind protect closing S.  */
@@ -3295,8 +3676,10 @@ usage: (make-network-process &rest ARGS)  */)
       emacs_close (s);
       s = -1;
 
+#ifdef WINDOWSNT
       if (xerrno == EINTR)
        goto retry_connect;
+#endif
     }
 
   if (s >= 0)
@@ -3372,8 +3755,6 @@ usage: (make-network-process &rest ARGS)  */)
        report_file_error ("make client process failed", contact);
     }
 
-#endif /* not TERM */
-
   inch = s;
   outch = s;
 
@@ -3395,6 +3776,7 @@ usage: (make-network-process &rest ARGS)  */)
 
   p->childp = contact;
   p->plist = Fcopy_sequence (Fplist_get (contact, QCplist));
+  p->type = Qnetwork;
 
   p->buffer = buffer;
   p->sentinel = sentinel;
@@ -3407,7 +3789,7 @@ usage: (make-network-process &rest ARGS)  */)
   p->pid = 0;
   p->infd  = inch;
   p->outfd = outch;
-  if (is_server && socktype == SOCK_STREAM)
+  if (is_server && socktype != SOCK_DGRAM)
     p->status = Qlisten;
 
   /* Make the process marker point into the process buffer (if any).  */
@@ -3606,10 +3988,10 @@ format; see the description of ADDRESS in `make-network-process'.  */)
 
 struct ifflag_def {
   int flag_bit;
-  char *flag_sym;
+  const char *flag_sym;
 };
 
-static struct ifflag_def ifflag_table[] = {
+static const struct ifflag_def ifflag_table[] = {
 #ifdef IFF_UP
   { IFF_UP,            "up" },
 #endif
@@ -3705,7 +4087,7 @@ FLAGS is the current flags of the interface.  */)
   if (ioctl (s, SIOCGIFFLAGS, &rq) == 0)
     {
       int flags = rq.ifr_flags;
-      struct ifflag_def *fp;
+      const struct ifflag_def *fp;
       int fnum;
 
       any++;
@@ -3811,19 +4193,9 @@ deactivate_process (proc)
     {
       /* Beware SIGCHLD hereabouts. */
       flush_pending_output (inchannel);
-#ifdef VMS
-      {
-       VMS_PROC_STUFF *get_vms_process_pointer (), *vs;
-       sys$dassgn (outchannel);
-       vs = get_vms_process_pointer (p->pid);
-       if (vs)
-         give_back_vms_process_stuff (vs);
-      }
-#else
       emacs_close (inchannel);
       if (outchannel >= 0 && outchannel != inchannel)
        emacs_close (outchannel);
-#endif
 
       p->infd  = -1;
       p->outfd = -1;
@@ -3892,9 +4264,9 @@ It is read into the process' buffers or given to their filter functions.
 Non-nil arg PROCESS means do not return until some output has been received
 from PROCESS.
 
-Non-nil second arg SECONDS and third arg MILLISEC are number of
-seconds and milliseconds to wait; return after that much time whether
-or not there is input.  If SECONDS is a floating point number,
+Non-nil second arg SECONDS and third arg MILLISEC are number of seconds
+and milliseconds to wait; return after that much time whether or not
+there is any subprocess output.  If SECONDS is a floating point number,
 it specifies a fractional number of seconds to wait.
 The MILLISEC argument is obsolete and should be avoided.
 
@@ -4113,6 +4485,7 @@ server_accept_connection (server, channel)
 
   p->childp = contact;
   p->plist = Fcopy_sequence (ps->plist);
+  p->type = Qnetwork;
 
   p->buffer = buffer;
   p->sentinel = ps->sentinel;
@@ -4188,7 +4561,7 @@ wait_reading_process_output_1 ()
 }
 
 /* Use a wrapper around select to work around a bug in gdb 5.3.
-   Normally, the wrapper is optimzed away by inlining.
+   Normally, the wrapper is optimized away by inlining.
 
    If emacs is stopped inside select, the gdb backtrace doesn't
    show the function which called select, so it is practically
@@ -4270,6 +4643,10 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
   FD_ZERO (&Connecting);
 #endif
 
+  if (time_limit == 0 && wait_proc && !NILP (Vinhibit_quit)
+      && !(CONSP (wait_proc->status) && EQ (XCAR (wait_proc->status), Qexit)))
+    message ("Blocking call to accept-process-output with quit inhibited!!");
+
   /* If wait_proc is a process to watch, set wait_channel accordingly.  */
   if (wait_proc != NULL)
     wait_channel = wait_proc->infd;
@@ -4286,16 +4663,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
       EMACS_SET_SECS_USECS (timeout, time_limit, microsecs);
       EMACS_ADD_TIME (end_time, end_time, timeout);
     }
-#ifdef POLL_INTERRUPTED_SYS_CALL
-  /* AlainF 5-Jul-1996
-     HP-UX 10.10 seem to have problems with signals coming in
-     Causes "poll: interrupted system call" messages when Emacs is run
-     in an X window
-     Turn off periodic alarms (in case they are in use),
-     and then turn off any other atimers.  */
-  stop_polling ();
-  turn_on_atimers (0);
-#endif /* POLL_INTERRUPTED_SYS_CALL */
 
   while (1)
     {
@@ -4308,12 +4675,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
        QUIT;
 #ifdef SYNC_INPUT
       else
-        {
-          if (interrupt_input_pending)
-            handle_async_input ();
-          if (pending_atimers)
-            do_pending_atimers ();
-        }
+       process_pending_signals ();
 #endif
 
       /* Exit now if the cell we're waiting for became non-nil.  */
@@ -4411,11 +4773,8 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
       /* If status of something has changed, and no input is
         available, notify the user of the change right away.  After
         this explicit check, we'll let the SIGCHLD handler zap
-        timeout to get our attention.  When Emacs is run
-        interactively, only do this with a nonzero DO_DISPLAY
-        argument, because status_notify triggers redisplay.  */
-      if (update_tick != process_tick
-         && (do_display || noninteractive))
+        timeout to get our attention.  */
+      if (update_tick != process_tick)
        {
          SELECT_TYPE Atemp;
 #ifdef NON_BLOCKING_CONNECT
@@ -4423,15 +4782,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
 #endif
 
          Atemp = input_wait_mask;
-#if 0
-          /* On Mac OS X 10.0, the SELECT system call always says input is
-             present (for reading) at stdin, even when none is.  This
-             causes the call to SELECT below to return 1 and
-             status_notify not to be called.  As a result output of
-             subprocesses are incorrectly discarded.
-         */
-          FD_CLR (0, &Atemp);
-#endif
          IF_NON_BLOCKING_CONNECT (Ctemp = connect_wait_mask);
 
          EMACS_SET_SECS_USECS (timeout, 0, 0);
@@ -4450,11 +4800,12 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
                 the loop, since timeout has already been zeroed out.  */
              clear_waiting_for_input ();
              status_notify (NULL);
+             if (do_display) redisplay_preserve_echo_area (13);
            }
        }
 
       /* Don't wait for output from a non-running process.  Just
-         read whatever data has already been received.  */
+        read whatever data has already been received.  */
       if (wait_proc && wait_proc->raw_status_new)
        update_status (wait_proc);
       if (wait_proc
@@ -4474,22 +4825,22 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
              if (nread == 0)
                break;
 
-              if (0 < nread)
-                {
+             if (0 < nread)
+               {
                  total_nread += nread;
                  got_some_input = 1;
                }
 #ifdef EIO
              else if (nread == -1 && EIO == errno)
-                break;
+               break;
 #endif
 #ifdef EAGAIN
              else if (nread == -1 && EAGAIN == errno)
-                break;
+               break;
 #endif
 #ifdef EWOULDBLOCK
              else if (nread == -1 && EWOULDBLOCK == errno)
-                break;
+               break;
 #endif
            }
          if (total_nread > 0 && do_display)
@@ -4583,8 +4934,14 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
              process_output_skip = 0;
            }
 #endif
-
-         nfds = select (max (max (max_process_desc, max_keyboard_desc),
+#if defined (USE_GTK) || defined (HAVE_GCONF)
+          nfds = xg_select
+#elif defined (HAVE_NS)
+         nfds = ns_select
+#else
+         nfds = select
+#endif
+                       (max (max (max_process_desc, max_keyboard_desc),
                              max_gpm_desc) + 1,
                         &Available,
 #ifdef NON_BLOCKING_CONNECT
@@ -4610,15 +4967,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
        {
          if (xerrno == EINTR)
            no_avail = 1;
-#ifdef ultrix
-         /* Ultrix select seems to return ENOMEM when it is
-            interrupted.  Treat it just like EINTR.  Bleah.  Note
-            that we want to test for the "ultrix" CPP symbol, not
-            "__ultrix__"; the latter is only defined under GCC, but
-            not by DEC's bundled CC.  -JimB  */
-         else if (xerrno == ENOMEM)
-           no_avail = 1;
-#endif
          else if (xerrno == EBADF)
            {
 #ifdef AIX
@@ -4644,19 +4992,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
          IF_NON_BLOCKING_CONNECT (check_connect = 0);
        }
 
-#if defined(sun) && !defined(USG5_4)
-      if (nfds > 0 && keyboard_bit_set (&Available)
-         && interrupt_input)
-       /* System sometimes fails to deliver SIGIO.
-
-          David J. Mackenzie says that Emacs doesn't compile under
-          Solaris if this code is enabled, thus the USG5_4 in the CPP
-          conditional.  "I haven't noticed any ill effects so far.
-          If you find a Solaris expert somewhere, they might know
-          better." */
-       kill (getpid (), SIGIO);
-#endif
-
 #if 0 /* When polling is used, interrupt_input is 0,
         so get_input_pending should read the input.
         So this should not be needed.  */
@@ -4811,7 +5146,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
                 available now and a closed pipe.
                 With luck, a closed pipe will be accompanied by
                 subprocess termination and SIGCHLD.  */
-             else if (nread == 0 && !NETCONN_P (proc))
+             else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc))
                ;
 #endif /* O_NDELAY */
 #endif /* O_NONBLOCK */
@@ -4829,17 +5164,22 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
                 It can't hurt.  */
              else if (nread == -1 && errno == EIO)
                {
-                 /* Clear the descriptor now, so we only raise the signal once.  */
-                 FD_CLR (channel, &input_wait_mask);
-                 FD_CLR (channel, &non_keyboard_wait_mask);
+                 /* Clear the descriptor now, so we only raise the
+                    signal once.  Don't do this if `process' is only
+                    a pty.  */
+                 if (XPROCESS (proc)->pid != -2)
+                   {
+                     FD_CLR (channel, &input_wait_mask);
+                     FD_CLR (channel, &non_keyboard_wait_mask);
 
-                 kill (getpid (), SIGCHLD);
+                     kill (getpid (), SIGCHLD);
+                   }
                }
 #endif /* HAVE_PTYS */
              /* If we can detect process termination, don't consider the process
                 gone just because its pipe is closed.  */
 #ifdef SIGCHLD
-             else if (nread == 0 && !NETCONN_P (proc))
+             else if (nread == 0 && !NETCONN_P (proc) && !SERIALCONN_P (proc))
                ;
 #endif
              else
@@ -4872,7 +5212,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
 
 #ifdef GNU_LINUX
              /* getsockopt(,,SO_ERROR,,) is said to hang on some systems.
-                So only use it on systems where it is known to work.  */
+                So only use it on systems where it is known to work.  */
              {
                int xlen = sizeof(xerrno);
                if (getsockopt(channel, SOL_SOCKET, SO_ERROR, &xerrno, &xlen))
@@ -4930,14 +5270,6 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
       clear_input_pending ();
       QUIT;
     }
-#ifdef POLL_INTERRUPTED_SYS_CALL
-  /* AlainF 5-Jul-1996
-     HP-UX 10.10 seems to have problems with signals coming in
-     Causes "poll: interrupted system call" messages when Emacs is run
-     in an X window
-     Turn periodic alarms back on */
-  start_polling ();
-#endif /* POLL_INTERRUPTED_SYS_CALL */
 
   return got_some_input;
 }
@@ -4981,43 +5313,13 @@ read_process_output (proc, channel)
   register int nbytes;
   char *chars;
   register Lisp_Object outstream;
-  register struct buffer *old = current_buffer;
   register struct Lisp_Process *p = XPROCESS (proc);
   register int opoint;
   struct coding_system *coding = proc_decode_coding_system[channel];
   int carryover = p->decoding_carryover;
   int readmax = 4096;
-
-#ifdef VMS
-  VMS_PROC_STUFF *vs, *get_vms_process_pointer();
-
-  vs = get_vms_process_pointer (p->pid);
-  if (vs)
-    {
-      if (!vs->iosb[0])
-       return (0);             /* Really weird if it does this */
-      if (!(vs->iosb[0] & 1))
-       return -1;              /* I/O error */
-    }
-  else
-    error ("Could not get VMS process pointer");
-  chars = vs->inputBuffer;
-  nbytes = clean_vms_buffer (chars, vs->iosb[1]);
-  if (nbytes <= 0)
-    {
-      start_vms_process_read (vs); /* Crank up the next read on the process */
-      return 1;                        /* Nothing worth printing, say we got 1 */
-    }
-  if (carryover > 0)
-    {
-      /* The data carried over in the previous decoding (which are at
-         the tail of decoding buffer) should be prepended to the new
-         data read to decode all together.  */
-      chars = (char *) alloca (nbytes + carryover);
-      bcopy (SDATA (p->decoding_buf), buf, carryover);
-      bcopy (vs->inputBuffer, chars + carryover, nbytes);
-    }
-#else /* not VMS */
+  int count = SPECPDL_INDEX ();
+  Lisp_Object odeactivate;
 
   chars = (char *) alloca (carryover + readmax);
   if (carryover)
@@ -5075,7 +5377,6 @@ read_process_output (proc, channel)
       else
        nbytes = nbytes + 1;
     }
-#endif /* not VMS */
 
   p->decoding_carryover = 0;
 
@@ -5091,15 +5392,16 @@ read_process_output (proc, channel)
   /* Now set NBYTES how many bytes we must decode.  */
   nbytes += carryover;
 
+  odeactivate = Vdeactivate_mark;
+  /* There's no good reason to let process filters change the current
+     buffer, and many callers of accept-process-output, sit-for, and
+     friends don't expect current-buffer to be changed from under them.  */
+  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+
   /* Read and dispose of the process output.  */
   outstream = p->filter;
   if (!NILP (outstream))
     {
-      /* We inhibit quit here instead of just catching it so that
-        hitting ^G when a filter happens to be running won't screw
-        it up.  */
-      int count = SPECPDL_INDEX ();
-      Lisp_Object odeactivate;
       Lisp_Object obuffer, okeymap;
       Lisp_Object text;
       int outer_running_asynch_code = running_asynch_code;
@@ -5107,10 +5409,12 @@ read_process_output (proc, channel)
 
       /* No need to gcpro these, because all we do with them later
         is test them for EQness, and none of them should be a string.  */
-      odeactivate = Vdeactivate_mark;
       XSETBUFFER (obuffer, current_buffer);
       okeymap = current_buffer->keymap;
 
+      /* We inhibit quit here instead of just catching it so that
+        hitting ^G when a filter happens to be running won't screw
+        it up.  */
       specbind (Qinhibit_quit, Qt);
       specbind (Qlast_nonmenu_event, Qt);
 
@@ -5179,9 +5483,6 @@ read_process_output (proc, channel)
       restore_search_regs ();
       running_asynch_code = outer_running_asynch_code;
 
-      /* Handling the process output should not deactivate the mark.  */
-      Vdeactivate_mark = odeactivate;
-
       /* Restore waiting_for_user_input_p as it was
         when we were called, in case the filter clobbered it.  */
       waiting_for_user_input_p = waiting;
@@ -5197,28 +5498,19 @@ read_process_output (proc, channel)
           cause trouble (for example it would make sit_for return).  */
        if (waiting_for_user_input_p == -1)
          record_asynch_buffer_change ();
-
-#ifdef VMS
-      start_vms_process_read (vs);
-#endif
-      unbind_to (count, Qnil);
-      return nbytes;
     }
 
   /* If no filter, write into buffer if it isn't dead.  */
-  if (!NILP (p->buffer) && !NILP (XBUFFER (p->buffer)->name))
+  else if (!NILP (p->buffer) && !NILP (XBUFFER (p->buffer)->name))
     {
       Lisp_Object old_read_only;
       int old_begv, old_zv;
       int old_begv_byte, old_zv_byte;
-      Lisp_Object odeactivate;
       int before, before_byte;
       int opoint_byte;
       Lisp_Object text;
       struct buffer *b;
 
-      odeactivate = Vdeactivate_mark;
-
       Fset_buffer (p->buffer);
       opoint = PT;
       opoint_byte = PT_BYTE;
@@ -5316,16 +5608,14 @@ read_process_output (proc, channel)
       if (old_begv != BEGV || old_zv != ZV)
        Fnarrow_to_region (make_number (old_begv), make_number (old_zv));
 
-      /* Handling the process output should not deactivate the mark.  */
-      Vdeactivate_mark = odeactivate;
 
       current_buffer->read_only = old_read_only;
       SET_PT_BOTH (opoint, opoint_byte);
-      set_buffer_internal (old);
     }
-#ifdef VMS
-  start_vms_process_read (vs);
-#endif
+  /* Handling the process output should not deactivate the mark.  */
+  Vdeactivate_mark = odeactivate;
+
+  unbind_to (count, Qnil);
   return nbytes;
 }
 
@@ -5347,10 +5637,6 @@ SIGTYPE
 send_process_trap ()
 {
   SIGNAL_THREAD_CHECK (SIGPIPE);
-#ifdef BSD4_1
-  sigrelse (SIGPIPE);
-  sigrelse (SIGALRM);
-#endif /* BSD4_1 */
   sigunblock (sigmask (SIGPIPE));
   longjmp (send_process_frame, 1);
 }
@@ -5381,10 +5667,6 @@ send_process (proc, buf, len, object)
 
   GCPRO1 (object);
 
-#ifdef VMS
-  VMS_PROC_STUFF *vs, *get_vms_process_pointer();
-#endif /* VMS */
-
   if (p->raw_status_new)
     update_status (p);
   if (! EQ (p->status, Qrun))
@@ -5453,7 +5735,8 @@ send_process (proc, buf, len, object)
        }
       else if (STRINGP (object))
        {
-         encode_coding_string (coding, object, 1);
+         encode_coding_object (coding, object, 0, 0, SCHARS (object),
+                               SBYTES (object), Qt);
        }
       else
        {
@@ -5462,17 +5745,10 @@ send_process (proc, buf, len, object)
        }
 
       len = coding->produced;
-      buf = SDATA (coding->dst_object);
+      object = coding->dst_object;
+      buf = SDATA (object);
     }
 
-#ifdef VMS
-  vs = get_vms_process_pointer (p->pid);
-  if (vs == 0)
-    error ("Could not find this process: %x", p->pid);
-  else if (write_to_vms_process (vs, buf, len))
-    ;
-#else /* not VMS */
-
   if (pty_max_bytes == 0)
     {
 #if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON)
@@ -5496,34 +5772,6 @@ send_process (proc, buf, len, object)
        {
          int this = len;
 
-         /* Decide how much data we can send in one batch.
-            Long lines need to be split into multiple batches.  */
-         if (p->pty_flag)
-           {
-             /* Starting this at zero is always correct when not the first
-                 iteration because the previous iteration ended by sending C-d.
-                It may not be correct for the first iteration
-                if a partial line was sent in a separate send_process call.
-                If that proves worth handling, we need to save linepos
-                in the process object.  */
-             int linepos = 0;
-             unsigned char *ptr = (unsigned char *) buf;
-             unsigned char *end = (unsigned char *) buf + len;
-
-             /* Scan through this text for a line that is too long.  */
-             while (ptr != end && linepos < pty_max_bytes)
-               {
-                 if (*ptr == '\n')
-                   linepos = 0;
-                 else
-                   linepos++;
-                 ptr++;
-               }
-             /* If we found one, break the line there
-                and put in a C-d to force the buffer through.  */
-             this = ptr - buf;
-           }
-
          /* Send this batch, using one or more write calls.  */
          while (this > 0)
            {
@@ -5627,30 +5875,18 @@ send_process (proc, buf, len, object)
              len -= rv;
              this -= rv;
            }
-
-         /* If we sent just part of the string, put in an EOF
-            to force it through, before we send the rest.  */
-         if (len > 0)
-           Fprocess_send_eof (proc);
        }
     }
-#endif /* not VMS */
   else
     {
       signal (SIGPIPE, old_sigpipe);
-#ifndef VMS
       proc = process_sent_to;
       p = XPROCESS (proc);
-#endif
       p->raw_status_new = 0;
       p->status = Fcons (Qexit, Fcons (make_number (256), Qnil));
       p->tick = ++process_tick;
       deactivate_process (proc);
-#ifdef VMS
-      error ("Error writing to process %s; closed it", SDATA (p->name));
-#else
       error ("SIGPIPE raised on process %s; closed it", SDATA (p->name));
-#endif
     }
 
   UNGCPRO;
@@ -5748,7 +5984,7 @@ return t unconditionally.  */)
   proc = get_process (process);
   p = XPROCESS (proc);
 
-  if (!EQ (p->childp, Qt))
+  if (!EQ (p->type, Qreal))
     error ("Process %s is not a subprocess",
           SDATA (p->name));
   if (p->infd < 0)
@@ -5791,7 +6027,7 @@ process_send_signal (process, signo, current_group, nomsg)
   proc = get_process (process);
   p = XPROCESS (proc);
 
-  if (!EQ (p->childp, Qt))
+  if (!EQ (p->type, Qreal))
     error ("Process %s is not a subprocess",
           SDATA (p->name));
   if (p->infd < 0)
@@ -5812,7 +6048,7 @@ process_send_signal (process, signo, current_group, nomsg)
         by sending an input character to it.  */
 
       /* TERMIOS is the latest and bestest, and seems most likely to
-         work.  If the system has it, use it.  */
+        work.  If the system has it, use it.  */
 #ifdef HAVE_TERMIOS
       struct termios t;
       cc_t *sig_char = NULL;
@@ -5950,24 +6186,15 @@ process_send_signal (process, signo, current_group, nomsg)
       p->status = Qrun;
       p->tick = ++process_tick;
       if (!nomsg)
-       status_notify (NULL);
+       {
+         status_notify (NULL);
+         redisplay_preserve_echo_area (13);
+       }
       break;
 #endif /* ! defined (SIGCONT) */
     case SIGINT:
-#ifdef VMS
-      send_process (proc, "\003", 1, Qnil);    /* ^C */
-      goto whoosh;
-#endif
     case SIGQUIT:
-#ifdef VMS
-      send_process (proc, "\031", 1, Qnil);    /* ^Y */
-      goto whoosh;
-#endif
     case SIGKILL:
-#ifdef VMS
-      sys$forcex (&(p->pid), 0, 1);
-      whoosh:
-#endif
       flush_pending_output (p->infd);
       break;
     }
@@ -6040,12 +6267,13 @@ See function `interrupt-process' for more details on usage.  */)
 DEFUN ("stop-process", Fstop_process, Sstop_process, 0, 2, 0,
        doc: /* Stop process PROCESS.  May be process or name of one.
 See function `interrupt-process' for more details on usage.
-If PROCESS is a network process, inhibit handling of incoming traffic.  */)
+If PROCESS is a network or serial process, inhibit handling of incoming
+traffic.  */)
      (process, current_group)
      Lisp_Object process, current_group;
 {
 #ifdef HAVE_SOCKETS
-  if (PROCESSP (process) && NETCONN_P (process))
+  if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process)))
     {
       struct Lisp_Process *p;
 
@@ -6071,12 +6299,13 @@ If PROCESS is a network process, inhibit handling of incoming traffic.  */)
 DEFUN ("continue-process", Fcontinue_process, Scontinue_process, 0, 2, 0,
        doc: /* Continue process PROCESS.  May be process or name of one.
 See function `interrupt-process' for more details on usage.
-If PROCESS is a network process, resume handling of incoming traffic.  */)
+If PROCESS is a network or serial process, resume handling of incoming
+traffic.  */)
      (process, current_group)
      Lisp_Object process, current_group;
 {
 #ifdef HAVE_SOCKETS
-  if (PROCESSP (process) && NETCONN_P (process))
+  if (PROCESSP (process) && (NETCONN_P (process) || SERIALCONN_P (process)))
     {
       struct Lisp_Process *p;
 
@@ -6087,6 +6316,13 @@ If PROCESS is a network process, resume handling of incoming traffic.  */)
        {
          FD_SET (p->infd, &input_wait_mask);
          FD_SET (p->infd, &non_keyboard_wait_mask);
+#ifdef WINDOWSNT
+         if (fd_info[ p->infd ].flags & FILE_SERIAL)
+           PurgeComm (fd_info[ p->infd ].hnd, PURGE_RXABORT | PURGE_RXCLEAR);
+#endif
+#ifdef HAVE_TERMIOS
+         tcflush (p->infd, TCIFLUSH);
+#endif
        }
       p->command = Qnil;
       return process;
@@ -6272,7 +6508,9 @@ PROCESS may be a process, a buffer, the name of a process or buffer, or
 nil, indicating the current buffer's process.
 If PROCESS is a network connection, or is a process communicating
 through a pipe (as opposed to a pty), then you cannot send any more
-text to PROCESS after you call this function.  */)
+text to PROCESS after you call this function.
+If PROCESS is a serial process, wait until all output written to the
+process has been transmitted to the serial port.  */)
      (process)
      Lisp_Object process;
 {
@@ -6297,11 +6535,16 @@ text to PROCESS after you call this function.  */)
       send_process (proc, "", 0, Qnil);
     }
 
-#ifdef VMS
-  send_process (proc, "\032", 1, Qnil);        /* ^z */
-#else
   if (XPROCESS (proc)->pty_flag)
     send_process (proc, "\004", 1, Qnil);
+  else if (EQ (XPROCESS (proc)->type, Qserial))
+    {
+#ifdef HAVE_TERMIOS
+      if (tcdrain (XPROCESS (proc)->outfd) != 0)
+       error ("tcdrain() failed: %s", emacs_strerror (errno));
+#endif
+      /* Do nothing on Windows because writes are blocking.  */
+    }
   else
     {
       int old_outfd, new_outfd;
@@ -6311,7 +6554,7 @@ text to PROCESS after you call this function.  */)
         for communication with the subprocess, call shutdown to cause EOF.
         (In some old system, shutdown to socketpair doesn't work.
         Then we just can't win.)  */
-      if (XPROCESS (proc)->pid == 0
+      if (EQ (XPROCESS (proc)->type, Qnetwork)
          || XPROCESS (proc)->outfd == XPROCESS (proc)->infd)
        shutdown (XPROCESS (proc)->outfd, 1);
       /* In case of socketpair, outfd == infd, so don't close it.  */
@@ -6336,7 +6579,6 @@ text to PROCESS after you call this function.  */)
 
       XPROCESS (proc)->outfd = new_outfd;
     }
-#endif /* VMS */
   return process;
 }
 
@@ -6355,7 +6597,7 @@ kill_buffer_processes (buffer)
       if (PROCESSP (proc)
          && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
        {
-         if (NETCONN_P (proc))
+         if (NETCONN_P (proc) || SERIALCONN_P (proc))
            Fdelete_process (proc);
          else if (XPROCESS (proc)->infd >= 0)
            process_send_signal (proc, SIGHUP, Qnil, 1);
@@ -6400,15 +6642,10 @@ sigchld_handler (signo)
 
   SIGNAL_THREAD_CHECK (signo);
 
-#ifdef BSD4_1
-  extern int sigheld;
-  sigheld |= sigbit (SIGCHLD);
-#endif
-
   while (1)
     {
       pid_t pid;
-      WAITTYPE w;
+      int w;
       Lisp_Object tail;
 
 #ifdef WNOHANG
@@ -6417,7 +6654,7 @@ sigchld_handler (signo)
 #endif /* no WUNTRACED */
       /* Keep trying to get a status until we get a definitive result.  */
       do
-        {
+       {
          errno = 0;
          pid = wait3 (&w, WNOHANG | WUNTRACED, 0);
        }
@@ -6428,15 +6665,6 @@ sigchld_handler (signo)
          /* PID == 0 means no processes found, PID == -1 means a real
             failure.  We have done all our job, so return.  */
 
-         /* USG systems forget handlers when they are used;
-            must reestablish each time */
-#if defined (USG) && !defined (POSIX_SIGNALS)
-         signal (signo, sigchld_handler);   /* WARNING - must come after wait3() */
-#endif
-#ifdef  BSD4_1
-         sigheld &= ~sigbit (SIGCHLD);
-         sigrelse (SIGCHLD);
-#endif
          errno = old_errno;
          return;
        }
@@ -6464,7 +6692,7 @@ sigchld_handler (signo)
        {
          proc = XCDR (XCAR (tail));
          p = XPROCESS (proc);
-         if (EQ (p->childp, Qt) && p->pid == pid)
+         if (EQ (p->type, Qreal) && p->pid == pid)
            break;
          p = 0;
        }
@@ -6484,12 +6712,10 @@ sigchld_handler (signo)
       /* Change the status of the process that was found.  */
       if (p != 0)
        {
-         union { int i; WAITTYPE wt; } u;
          int clear_desc_flag = 0;
 
          p->tick = ++process_tick;
-         u.wt = w;
-         p->raw_status = u.i;
+         p->raw_status = w;
          p->raw_status_new = 1;
 
          /* If process has terminated, stop waiting for its output.  */
@@ -6520,7 +6746,7 @@ sigchld_handler (signo)
          if (WIFEXITED (w))
            synch_process_retcode = WRETCODE (w);
          else if (WIFSIGNALED (w))
-            synch_process_termsig = WTERMSIG (w);
+           synch_process_termsig = WTERMSIG (w);
 
          /* Tell wait_reading_process_output that it needs to wake up and
             look around.  */
@@ -6538,10 +6764,7 @@ sigchld_handler (signo)
         to use up all the processes that have something to tell us.  */
 #if (defined WINDOWSNT \
      || (defined USG && !defined GNU_LINUX \
-         && !(defined HPUX && defined WNOHANG)))
-#if defined (USG) && ! defined (POSIX_SIGNALS)
-      signal (signo, sigchld_handler);
-#endif
+        && !(defined HPUX && defined WNOHANG)))
       errno = old_errno;
       return;
 #endif /* USG, but not HPUX with WNOHANG */
@@ -6588,6 +6811,11 @@ exec_sentinel (proc, reason)
   XSETBUFFER (obuffer, current_buffer);
   okeymap = current_buffer->keymap;
 
+  /* There's no good reason to let sentinels change the current
+     buffer, and many callers of accept-process-output, sit-for, and
+     friends don't expect current-buffer to be changed from under them.  */
+  record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+
   sentinel = p->sentinel;
   if (NILP (sentinel))
     return;
@@ -6598,7 +6826,7 @@ exec_sentinel (proc, reason)
   record_unwind_protect (exec_sentinel_unwind, Fcons (proc, sentinel));
   /* Inhibit quit so that random quits don't screw up a running filter.  */
   specbind (Qinhibit_quit, Qt);
-  specbind (Qlast_nonmenu_event, Qt);
+  specbind (Qlast_nonmenu_event, Qt); /* Why? --Stef  */
 
   /* In case we get recursively called,
      and we already saved the match data nonrecursively,
@@ -6686,7 +6914,8 @@ status_notify (deleting_process)
          while (! EQ (p->filter, Qt)
                 && ! EQ (p->status, Qconnect)
                 && ! EQ (p->status, Qlisten)
-                && ! EQ (p->command, Qt)  /* Network process not stopped.  */
+                /* Network or serial process not stopped:  */
+                && ! EQ (p->command, Qt)
                 && p->infd >= 0
                 && p != deleting_process
                 && read_process_output (proc, p->infd) > 0);
@@ -6724,13 +6953,11 @@ status_notify (deleting_process)
             when a process becomes runnable.  */
          else if (!EQ (symbol, Qrun) && !NILP (buffer))
            {
-             Lisp_Object ro, tem;
+             Lisp_Object tem;
              struct buffer *old = current_buffer;
              int opoint, opoint_byte;
              int before, before_byte;
 
-             ro = XBUFFER (buffer)->read_only;
-
              /* Avoid error if buffer is deleted
                 (probably that's why the process is dead, too) */
              if (NILP (XBUFFER (buffer)->name))
@@ -6771,8 +6998,6 @@ status_notify (deleting_process)
     } /* end for */
 
   update_mode_lines++;  /* in case buffers use %s in mode-line-format */
-  redisplay_preserve_echo_area (13);
-
   UNGCPRO;
 }
 
@@ -6934,6 +7159,77 @@ keyboard_bit_set (mask)
   return 0;
 }
 \f
+/* Enumeration of and access to system processes a-la ps(1).  */
+
+DEFUN ("list-system-processes", Flist_system_processes, Slist_system_processes,
+       0, 0, 0,
+       doc: /* Return a list of numerical process IDs of all running processes.
+If this functionality is unsupported, return nil.
+
+See `process-attributes' for getting attributes of a process given its ID.  */)
+    ()
+{
+  return list_system_processes ();
+}
+
+DEFUN ("process-attributes", Fprocess_attributes,
+       Sprocess_attributes, 1, 1, 0,
+       doc: /* Return attributes of the process given by its PID, a number.
+
+Value is an alist where each element is a cons cell of the form
+
+    \(KEY . VALUE)
+
+If this functionality is unsupported, the value is nil.
+
+See `list-system-processes' for getting a list of all process IDs.
+
+The KEYs of the attributes that this function may return are listed
+below, together with the type of the associated VALUE (in parentheses).
+Not all platforms support all of these attributes; unsupported
+attributes will not appear in the returned alist.
+Unless explicitly indicated otherwise, numbers can have either
+integer or floating point values.
+
+ euid    -- Effective user User ID of the process (number)
+ user    -- User name corresponding to euid (string)
+ egid    -- Effective user Group ID of the process (number)
+ group   -- Group name corresponding to egid (string)
+ comm    -- Command name (executable name only) (string)
+ state   -- Process state code, such as "S", "R", or "T" (string)
+ ppid    -- Parent process ID (number)
+ pgrp    -- Process group ID (number)
+ sess    -- Session ID, i.e. process ID of session leader (number)
+ ttname  -- Controlling tty name (string)
+ tpgid   -- ID of foreground process group on the process's tty (number)
+ minflt  -- number of minor page faults (number)
+ majflt  -- number of major page faults (number)
+ cminflt -- cumulative number of minor page faults (number)
+ cmajflt -- cumulative number of major page faults (number)
+ utime   -- user time used by the process, in the (HIGH LOW USEC) format
+ stime   -- system time used by the process, in the (HIGH LOW USEC) format
+ time    -- sum of utime and stime, in the (HIGH LOW USEC) format
+ cutime  -- user time used by the process and its children, (HIGH LOW USEC)
+ cstime  -- system time used by the process and its children, (HIGH LOW USEC)
+ ctime   -- sum of cutime and cstime, in the (HIGH LOW USEC) format
+ pri     -- priority of the process (number)
+ nice    -- nice value of the process (number)
+ thcount -- process thread count (number)
+ start   -- time the process started, in the (HIGH LOW USEC) format
+ vsize   -- virtual memory size of the process in KB's (number)
+ rss     -- resident set size of the process in KB's (number)
+ etime   -- elapsed time the process is running, in (HIGH LOW USEC) format
+ pcpu    -- percents of CPU time used by the process (floating-point number)
+ pmem    -- percents of total physical memory used by process's resident set
+              (floating-point number)
+ args    -- command line which invoked the process (string).  */)
+    (pid)
+
+    Lisp_Object pid;
+{
+  return system_process_attributes (pid);
+}
+\f
 void
 init_process ()
 {
@@ -6988,10 +7284,10 @@ init_process ()
 #ifdef HAVE_SOCKETS
  {
    Lisp_Object subfeatures = Qnil;
-   struct socket_options *sopt;
+   const struct socket_options *sopt;
 
 #define ADD_SUBFEATURE(key, val) \
-  subfeatures = Fcons (Fcons (key, Fcons (val, Qnil)), subfeatures)
+  subfeatures = pure_cons (pure_cons (key, pure_cons (val, Qnil)), subfeatures)
 
 #ifdef NON_BLOCKING_CONNECT
    ADD_SUBFEATURE (QCnowait, Qt);
@@ -6999,6 +7295,9 @@ init_process ()
 #ifdef DATAGRAM_SOCKETS
    ADD_SUBFEATURE (QCtype, Qdatagram);
 #endif
+#ifdef HAVE_SEQPACKET
+   ADD_SUBFEATURE (QCtype, Qseqpacket);
+#endif
 #ifdef HAVE_LOCAL_SOCKETS
    ADD_SUBFEATURE (QCfamily, Qlocal);
 #endif
@@ -7009,18 +7308,18 @@ init_process ()
 #ifdef HAVE_GETSOCKNAME
    ADD_SUBFEATURE (QCservice, Qt);
 #endif
-#if !defined(TERM) && (defined(O_NONBLOCK) || defined(O_NDELAY))
+#if defined(O_NONBLOCK) || defined(O_NDELAY)
    ADD_SUBFEATURE (QCserver, Qt);
 #endif
 
    for (sopt = socket_options; sopt->name; sopt++)
-     subfeatures = Fcons (intern (sopt->name), subfeatures);
+     subfeatures = pure_cons (intern_c_string (sopt->name), subfeatures);
 
-   Fprovide (intern ("make-network-process"), subfeatures);
+   Fprovide (intern_c_string ("make-network-process"), subfeatures);
  }
 #endif /* HAVE_SOCKETS */
 
-#if defined (DARWIN) || defined (MAC_OSX)
+#if defined (DARWIN_OS)
   /* PTYs are broken on Darwin < 6, but are sometimes useful for interactive
      processes.  As such, we only change the default value.  */
  if (initialized)
@@ -7037,76 +7336,111 @@ init_process ()
 void
 syms_of_process ()
 {
-  Qprocessp = intern ("processp");
+  Qprocessp = intern_c_string ("processp");
   staticpro (&Qprocessp);
-  Qrun = intern ("run");
+  Qrun = intern_c_string ("run");
   staticpro (&Qrun);
-  Qstop = intern ("stop");
+  Qstop = intern_c_string ("stop");
   staticpro (&Qstop);
-  Qsignal = intern ("signal");
+  Qsignal = intern_c_string ("signal");
   staticpro (&Qsignal);
 
   /* Qexit is already staticpro'd by syms_of_eval; don't staticpro it
      here again.
 
-     Qexit = intern ("exit");
+     Qexit = intern_c_string ("exit");
      staticpro (&Qexit); */
 
-  Qopen = intern ("open");
+  Qopen = intern_c_string ("open");
   staticpro (&Qopen);
-  Qclosed = intern ("closed");
+  Qclosed = intern_c_string ("closed");
   staticpro (&Qclosed);
-  Qconnect = intern ("connect");
+  Qconnect = intern_c_string ("connect");
   staticpro (&Qconnect);
-  Qfailed = intern ("failed");
+  Qfailed = intern_c_string ("failed");
   staticpro (&Qfailed);
-  Qlisten = intern ("listen");
+  Qlisten = intern_c_string ("listen");
   staticpro (&Qlisten);
-  Qlocal = intern ("local");
+  Qlocal = intern_c_string ("local");
   staticpro (&Qlocal);
-  Qipv4 = intern ("ipv4");
+  Qipv4 = intern_c_string ("ipv4");
   staticpro (&Qipv4);
 #ifdef AF_INET6
-  Qipv6 = intern ("ipv6");
+  Qipv6 = intern_c_string ("ipv6");
   staticpro (&Qipv6);
 #endif
-  Qdatagram = intern ("datagram");
+  Qdatagram = intern_c_string ("datagram");
   staticpro (&Qdatagram);
-
-  QCname = intern (":name");
+  Qseqpacket = intern_c_string ("seqpacket");
+  staticpro (&Qseqpacket);
+
+  QCport = intern_c_string (":port");
+  staticpro (&QCport);
+  QCspeed = intern_c_string (":speed");
+  staticpro (&QCspeed);
+  QCprocess = intern_c_string (":process");
+  staticpro (&QCprocess);
+
+  QCbytesize = intern_c_string (":bytesize");
+  staticpro (&QCbytesize);
+  QCstopbits = intern_c_string (":stopbits");
+  staticpro (&QCstopbits);
+  QCparity = intern_c_string (":parity");
+  staticpro (&QCparity);
+  Qodd = intern_c_string ("odd");
+  staticpro (&Qodd);
+  Qeven = intern_c_string ("even");
+  staticpro (&Qeven);
+  QCflowcontrol = intern_c_string (":flowcontrol");
+  staticpro (&QCflowcontrol);
+  Qhw = intern_c_string ("hw");
+  staticpro (&Qhw);
+  Qsw = intern_c_string ("sw");
+  staticpro (&Qsw);
+  QCsummary = intern_c_string (":summary");
+  staticpro (&QCsummary);
+
+  Qreal = intern_c_string ("real");
+  staticpro (&Qreal);
+  Qnetwork = intern_c_string ("network");
+  staticpro (&Qnetwork);
+  Qserial = intern_c_string ("serial");
+  staticpro (&Qserial);
+
+  QCname = intern_c_string (":name");
   staticpro (&QCname);
-  QCbuffer = intern (":buffer");
+  QCbuffer = intern_c_string (":buffer");
   staticpro (&QCbuffer);
-  QChost = intern (":host");
+  QChost = intern_c_string (":host");
   staticpro (&QChost);
-  QCservice = intern (":service");
+  QCservice = intern_c_string (":service");
   staticpro (&QCservice);
-  QCtype = intern (":type");
+  QCtype = intern_c_string (":type");
   staticpro (&QCtype);
-  QClocal = intern (":local");
+  QClocal = intern_c_string (":local");
   staticpro (&QClocal);
-  QCremote = intern (":remote");
+  QCremote = intern_c_string (":remote");
   staticpro (&QCremote);
-  QCcoding = intern (":coding");
+  QCcoding = intern_c_string (":coding");
   staticpro (&QCcoding);
-  QCserver = intern (":server");
+  QCserver = intern_c_string (":server");
   staticpro (&QCserver);
-  QCnowait = intern (":nowait");
+  QCnowait = intern_c_string (":nowait");
   staticpro (&QCnowait);
-  QCsentinel = intern (":sentinel");
+  QCsentinel = intern_c_string (":sentinel");
   staticpro (&QCsentinel);
-  QClog = intern (":log");
+  QClog = intern_c_string (":log");
   staticpro (&QClog);
-  QCnoquery = intern (":noquery");
+  QCnoquery = intern_c_string (":noquery");
   staticpro (&QCnoquery);
-  QCstop = intern (":stop");
+  QCstop = intern_c_string (":stop");
   staticpro (&QCstop);
-  QCoptions = intern (":options");
+  QCoptions = intern_c_string (":options");
   staticpro (&QCoptions);
-  QCplist = intern (":plist");
+  QCplist = intern_c_string (":plist");
   staticpro (&QCplist);
 
-  Qlast_nonmenu_event = intern ("last-nonmenu-event");
+  Qlast_nonmenu_event = intern_c_string ("last-nonmenu-event");
   staticpro (&Qlast_nonmenu_event);
 
   staticpro (&Vprocess_alist);
@@ -7114,6 +7448,69 @@ syms_of_process ()
   staticpro (&deleted_pid_list);
 #endif
 
+  Qeuid = intern_c_string ("euid");
+  staticpro (&Qeuid);
+  Qegid = intern_c_string ("egid");
+  staticpro (&Qegid);
+  Quser = intern_c_string ("user");
+  staticpro (&Quser);
+  Qgroup = intern_c_string ("group");
+  staticpro (&Qgroup);
+  Qcomm = intern_c_string ("comm");
+  staticpro (&Qcomm);
+  Qstate = intern_c_string ("state");
+  staticpro (&Qstate);
+  Qppid = intern_c_string ("ppid");
+  staticpro (&Qppid);
+  Qpgrp = intern_c_string ("pgrp");
+  staticpro (&Qpgrp);
+  Qsess = intern_c_string ("sess");
+  staticpro (&Qsess);
+  Qttname = intern_c_string ("ttname");
+  staticpro (&Qttname);
+  Qtpgid = intern_c_string ("tpgid");
+  staticpro (&Qtpgid);
+  Qminflt = intern_c_string ("minflt");
+  staticpro (&Qminflt);
+  Qmajflt = intern_c_string ("majflt");
+  staticpro (&Qmajflt);
+  Qcminflt = intern_c_string ("cminflt");
+  staticpro (&Qcminflt);
+  Qcmajflt = intern_c_string ("cmajflt");
+  staticpro (&Qcmajflt);
+  Qutime = intern_c_string ("utime");
+  staticpro (&Qutime);
+  Qstime = intern_c_string ("stime");
+  staticpro (&Qstime);
+  Qtime = intern_c_string ("time");
+  staticpro (&Qtime);
+  Qcutime = intern_c_string ("cutime");
+  staticpro (&Qcutime);
+  Qcstime = intern_c_string ("cstime");
+  staticpro (&Qcstime);
+  Qctime = intern_c_string ("ctime");
+  staticpro (&Qctime);
+  Qpri = intern_c_string ("pri");
+  staticpro (&Qpri);
+  Qnice = intern_c_string ("nice");
+  staticpro (&Qnice);
+  Qthcount = intern_c_string ("thcount");
+  staticpro (&Qthcount);
+  Qstart = intern_c_string ("start");
+  staticpro (&Qstart);
+  Qvsize = intern_c_string ("vsize");
+  staticpro (&Qvsize);
+  Qrss = intern_c_string ("rss");
+  staticpro (&Qrss);
+  Qetime = intern_c_string ("etime");
+  staticpro (&Qetime);
+  Qpcpu = intern_c_string ("pcpu");
+  staticpro (&Qpcpu);
+  Qpmem = intern_c_string ("pmem");
+  staticpro (&Qpmem);
+  Qargs = intern_c_string ("args");
+  staticpro (&Qargs);
+
   DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
               doc: /* *Non-nil means delete processes immediately when they exit.
 A value of nil means don't delete them until `list-processes' is run.  */);
@@ -7170,6 +7567,10 @@ The variable takes effect when `start-process' is called.  */);
   defsubr (&Slist_processes);
   defsubr (&Sprocess_list);
   defsubr (&Sstart_process);
+#ifdef HAVE_SERIAL
+  defsubr (&Sserial_process_configure);
+  defsubr (&Smake_serial_process);
+#endif /* HAVE_SERIAL  */
 #ifdef HAVE_SOCKETS
   defsubr (&Sset_network_process_option);
   defsubr (&Smake_network_process);
@@ -7199,11 +7600,13 @@ The variable takes effect when `start-process' is called.  */);
   defsubr (&Sprocess_send_eof);
   defsubr (&Ssignal_process);
   defsubr (&Swaiting_for_user_input_p);
-/*  defsubr (&Sprocess_connection); */
+  defsubr (&Sprocess_type);
   defsubr (&Sset_process_coding_system);
   defsubr (&Sprocess_coding_system);
   defsubr (&Sset_process_filter_multibyte);
   defsubr (&Sprocess_filter_multibyte_p);
+  defsubr (&Slist_system_processes);
+  defsubr (&Sprocess_attributes);
 }
 
 \f
@@ -7211,6 +7614,13 @@ The variable takes effect when `start-process' is called.  */);
 
 #include <sys/types.h>
 #include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 
 #include "lisp.h"
 #include "systime.h"
@@ -7224,7 +7634,12 @@ extern int frame_garbaged;
 extern EMACS_TIME timer_check ();
 extern int timers_run;
 
-Lisp_Object QCtype;
+Lisp_Object QCtype, QCname;
+
+Lisp_Object Qeuid, Qegid, Qcomm, Qstate, Qppid, Qpgrp, Qsess, Qttname, Qtpgid;
+Lisp_Object Qminflt, Qmajflt, Qcminflt, Qcmajflt, Qutime, Qstime, Qcstime;
+Lisp_Object Qcutime, Qpri, Qnice, Qthcount, Qstart, Qvsize, Qrss, Qargs;
+Lisp_Object Quser, Qgroup, Qetime, Qpcpu, Qpmem, Qtime, Qctime;
 
 /* As described above, except assuming that there are no subprocesses:
 
@@ -7402,7 +7817,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
          else
            error ("select error: %s", emacs_strerror (xerrno));
        }
-#ifdef sun
+#ifdef SOLARIS2
       else if (nfds > 0 && (waitchannels & 1)  && interrupt_input)
        /* System sometimes fails to deliver SIGIO.  */
        kill (getpid (), SIGIO);
@@ -7486,6 +7901,75 @@ kill_buffer_processes (buffer)
 {
 }
 
+DEFUN ("list-system-processes", Flist_system_processes, Slist_system_processes,
+       0, 0, 0,
+       doc: /* Return a list of numerical process IDs of all running processes.
+If this functionality is unsupported, return nil.
+
+See `process-attributes' for getting attributes of a process given its ID.  */)
+    ()
+{
+  return list_system_processes ();
+}
+
+DEFUN ("process-attributes", Fprocess_attributes,
+       Sprocess_attributes, 1, 1, 0,
+       doc: /* Return attributes of the process given by its PID, a number.
+
+Value is an alist where each element is a cons cell of the form
+
+    \(KEY . VALUE)
+
+If this functionality is unsupported, the value is nil.
+
+See `list-system-processes' for getting a list of all process IDs.
+
+The KEYs of the attributes that this function may return are listed
+below, together with the type of the associated VALUE (in parentheses).
+Not all platforms support all of these attributes; unsupported
+attributes will not appear in the returned alist.
+Unless explicitly indicated otherwise, numbers can have either
+integer or floating point values.
+
+ euid    -- Effective user User ID of the process (number)
+ user    -- User name corresponding to euid (string)
+ egid    -- Effective user Group ID of the process (number)
+ group   -- Group name corresponding to egid (string)
+ comm    -- Command name (executable name only) (string)
+ state   -- Process state code, such as "S", "R", or "T" (string)
+ ppid    -- Parent process ID (number)
+ pgrp    -- Process group ID (number)
+ sess    -- Session ID, i.e. process ID of session leader (number)
+ ttname  -- Controlling tty name (string)
+ tpgid   -- ID of foreground process group on the process's tty (number)
+ minflt  -- number of minor page faults (number)
+ majflt  -- number of major page faults (number)
+ cminflt -- cumulative number of minor page faults (number)
+ cmajflt -- cumulative number of major page faults (number)
+ utime   -- user time used by the process, in the (HIGH LOW USEC) format
+ stime   -- system time used by the process, in the (HIGH LOW USEC) format
+ time    -- sum of utime and stime, in the (HIGH LOW USEC) format
+ cutime  -- user time used by the process and its children, (HIGH LOW USEC)
+ cstime  -- system time used by the process and its children, (HIGH LOW USEC)
+ ctime   -- sum of cutime and cstime, in the (HIGH LOW USEC) format
+ pri     -- priority of the process (number)
+ nice    -- nice value of the process (number)
+ thcount -- process thread count (number)
+ start   -- time the process started, in the (HIGH LOW USEC) format
+ vsize   -- virtual memory size of the process in KB's (number)
+ rss     -- resident set size of the process in KB's (number)
+ etime   -- elapsed time the process is running, in (HIGH LOW USEC) format
+ pcpu    -- percents of CPU time used by the process (floating-point number)
+ pmem    -- percents of total physical memory used by process's resident set
+              (floating-point number)
+ args    -- command line which invoked the process (string).   */)
+    (pid)
+
+    Lisp_Object pid;
+{
+  return system_process_attributes (pid);
+}
+
 void
 init_process ()
 {
@@ -7494,11 +7978,81 @@ init_process ()
 void
 syms_of_process ()
 {
-  QCtype = intern (":type");
+  QCtype = intern_c_string (":type");
   staticpro (&QCtype);
+  QCname = intern_c_string (":name");
+  staticpro (&QCname);
+  QCtype = intern_c_string (":type");
+  staticpro (&QCtype);
+  QCname = intern_c_string (":name");
+  staticpro (&QCname);
+  Qeuid = intern_c_string ("euid");
+  staticpro (&Qeuid);
+  Qegid = intern_c_string ("egid");
+  staticpro (&Qegid);
+  Quser = intern_c_string ("user");
+  staticpro (&Quser);
+  Qgroup = intern_c_string ("group");
+  staticpro (&Qgroup);
+  Qcomm = intern_c_string ("comm");
+  staticpro (&Qcomm);
+  Qstate = intern_c_string ("state");
+  staticpro (&Qstate);
+  Qppid = intern_c_string ("ppid");
+  staticpro (&Qppid);
+  Qpgrp = intern_c_string ("pgrp");
+  staticpro (&Qpgrp);
+  Qsess = intern_c_string ("sess");
+  staticpro (&Qsess);
+  Qttname = intern_c_string ("ttname");
+  staticpro (&Qttname);
+  Qtpgid = intern_c_string ("tpgid");
+  staticpro (&Qtpgid);
+  Qminflt = intern_c_string ("minflt");
+  staticpro (&Qminflt);
+  Qmajflt = intern_c_string ("majflt");
+  staticpro (&Qmajflt);
+  Qcminflt = intern_c_string ("cminflt");
+  staticpro (&Qcminflt);
+  Qcmajflt = intern_c_string ("cmajflt");
+  staticpro (&Qcmajflt);
+  Qutime = intern_c_string ("utime");
+  staticpro (&Qutime);
+  Qstime = intern_c_string ("stime");
+  staticpro (&Qstime);
+  Qtime = intern_c_string ("time");
+  staticpro (&Qtime);
+  Qcutime = intern_c_string ("cutime");
+  staticpro (&Qcutime);
+  Qcstime = intern_c_string ("cstime");
+  staticpro (&Qcstime);
+  Qctime = intern_c_string ("ctime");
+  staticpro (&Qctime);
+  Qpri = intern_c_string ("pri");
+  staticpro (&Qpri);
+  Qnice = intern_c_string ("nice");
+  staticpro (&Qnice);
+  Qthcount = intern_c_string ("thcount");
+  staticpro (&Qthcount);
+  Qstart = intern_c_string ("start");
+  staticpro (&Qstart);
+  Qvsize = intern_c_string ("vsize");
+  staticpro (&Qvsize);
+  Qrss = intern_c_string ("rss");
+  staticpro (&Qrss);
+  Qetime = intern_c_string ("etime");
+  staticpro (&Qetime);
+  Qpcpu = intern_c_string ("pcpu");
+  staticpro (&Qpcpu);
+  Qpmem = intern_c_string ("pmem");
+  staticpro (&Qpmem);
+  Qargs = intern_c_string ("args");
+  staticpro (&Qargs);
 
   defsubr (&Sget_buffer_process);
   defsubr (&Sprocess_inherit_coding_system_flag);
+  defsubr (&Slist_system_processes);
+  defsubr (&Sprocess_attributes);
 }
 
 \f