* callproc.c (Fgetenv_internal): Doc fix.
[bpt/emacs.git] / src / process.c
index 5084bc8..b3271d3 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 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -33,8 +33,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef subprocesses
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
 #include <errno.h>
 #include <setjmp.h>
 #include <sys/types.h>         /* some typedefs are used in sys/file.h */
@@ -43,10 +41,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef HAVE_INTTYPES_H
 #include <inttypes.h>
 #endif
-
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#include <grp.h>
+#ifdef STDC_HEADERS
+#include <stdlib.h>
 #endif
 
 #ifdef HAVE_UNISTD_H
@@ -153,7 +149,7 @@ extern Lisp_Object QCfilter;
 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;
+Lisp_Object Quser, Qgroup, Qetime, Qpcpu, Qpmem, Qtime, Qctime;
 
 #ifdef HAVE_SOCKETS
 #define NETCONN_P(p) (EQ (XPROCESS (p)->type, Qnetwork))
@@ -561,7 +557,7 @@ 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)
              {
@@ -1484,7 +1480,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);
@@ -1500,7 +1496,7 @@ 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);
@@ -2271,6 +2267,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 build_string ("");
+
   switch (sa->sa_family)
     {
     case AF_INET:
@@ -2280,14 +2282,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);
@@ -2308,11 +2310,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;
     }
 
@@ -3341,7 +3343,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;
 
@@ -3462,7 +3464,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 signaled 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]);
 
@@ -4544,12 +4546,12 @@ 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 ();
-        }
+       {
+         if (interrupt_input_pending)
+           handle_async_input ();
+         if (pending_atimers)
+           do_pending_atimers ();
+       }
 #endif
 
       /* Exit now if the cell we're waiting for became non-nil.  */
@@ -4681,7 +4683,7 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
        }
 
       /* 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
@@ -4701,22 +4703,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)
@@ -4811,11 +4813,11 @@ wait_reading_process_output (time_limit, microsecs, read_kbd, do_display,
            }
 #endif
 #ifdef HAVE_NS
-          nfds = ns_select
+         nfds = ns_select
 #else
-          nfds = select
+         nfds = select
 #endif
-                        (max (max (max_process_desc, max_keyboard_desc),
+                       (max (max (max_process_desc, max_keyboard_desc),
                              max_gpm_desc) + 1,
                         &Available,
 #ifdef NON_BLOCKING_CONNECT
@@ -5081,7 +5083,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))
@@ -5648,7 +5650,7 @@ send_process (proc, buf, len, object)
          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.
+                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
@@ -5952,7 +5954,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;
@@ -6555,7 +6557,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);
        }
@@ -6652,7 +6654,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.  */
@@ -6670,7 +6672,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)))
+        && !(defined HPUX && defined WNOHANG)))
 #if defined (USG) && ! defined (POSIX_SIGNALS)
       signal (signo, sigchld_handler);
 #endif
@@ -7069,422 +7071,6 @@ keyboard_bit_set (mask)
 \f
 /* Enumeration of and access to system processes a-la ps(1).  */
 
-#if HAVE_PROCFS
-
-/* Process enumeration and access via /proc.  */
-
-static Lisp_Object
-procfs_list_system_processes ()
-{
-  Lisp_Object procdir, match, proclist, next;
-  struct gcpro gcpro1, gcpro2;
-  register Lisp_Object tail;
-
-  GCPRO2 (procdir, match);
-  /* For every process on the system, there's a directory in the
-     "/proc" pseudo-directory whose name is the numeric ID of that
-     process.  */
-  procdir = build_string ("/proc");
-  match = build_string ("[0-9]+");
-  proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil);
-
-  /* `proclist' gives process IDs as strings.  Destructively convert
-     each string into a number.  */
-  for (tail = proclist; CONSP (tail); tail = next)
-    {
-      next = XCDR (tail);
-      XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil));
-    }
-  UNGCPRO;
-
-  /* directory_files_internal returns the files in reverse order; undo
-     that.  */
-  proclist = Fnreverse (proclist);
-  return proclist;
-}
-
-static void
-time_from_jiffies (unsigned long long tval, long hz,
-                  time_t *sec, unsigned *usec)
-{
-  unsigned long long ullsec;
-
-  *sec = tval / hz;
-  ullsec = *sec;
-  tval -= ullsec * hz;
-  /* Careful: if HZ > 1 million, then integer division by it yields zero.  */
-  if (hz <= 1000000)
-    *usec = tval * 1000000 / hz;
-  else
-    *usec = tval / (hz / 1000000);
-}
-
-static Lisp_Object
-ltime_from_jiffies (unsigned long long tval, long hz)
-{
-  time_t sec;
-  unsigned usec;
-
-  time_from_jiffies (tval, hz, &sec, &usec);
-
-  return list3 (make_number ((sec >> 16) & 0xffff),
-               make_number (sec & 0xffff),
-               make_number (usec));
-}
-
-static void
-get_up_time (time_t *sec, unsigned *usec)
-{
-  FILE *fup;
-
-  *sec = *usec = 0;
-
-  BLOCK_INPUT;
-  fup = fopen ("/proc/uptime", "r");
-
-  if (fup)
-    {
-      double uptime, idletime;
-
-      /* The numbers in /proc/uptime use C-locale decimal point, but
-        we already set ourselves to the C locale (see `fixup_locale'
-        in emacs.c).  */
-      if (2 <= fscanf (fup, "%lf %lf", &uptime, &idletime))
-       {
-         *sec = uptime;
-         *usec = (uptime - *sec) * 1000000;
-       }
-      fclose (fup);
-    }
-  UNBLOCK_INPUT;
-}
-
-#define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff)
-#define MINOR(d) (((unsigned)(d) & 0xff) | (((unsigned)(d) & 0xfff00000) >> 12))
-
-static Lisp_Object
-procfs_ttyname (rdev)
-{
-  FILE *fdev = NULL;
-  char name[PATH_MAX];
-
-  BLOCK_INPUT;
-  fdev = fopen ("/proc/tty/drivers", "r");
-
-  if (fdev)
-    {
-      unsigned major;
-      unsigned long minor_beg, minor_end;
-      char minor[25];  /* 2 32-bit numbers + dash */
-      char *endp;
-
-      while (!feof (fdev) && !ferror (fdev))
-       {
-         if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor)
-             && major == MAJOR (rdev))
-           {
-             minor_beg = strtoul (minor, &endp, 0);
-             if (*endp == '\0')
-               minor_end = minor_beg;
-             else if (*endp == '-')
-               minor_end = strtoul (endp + 1, &endp, 0);
-             else
-               continue;
-
-             if (MINOR (rdev) >= minor_beg && MINOR (rdev) <= minor_end)
-               {
-                 sprintf (name + strlen (name), "%lu", MINOR (rdev));
-                 break;
-               }
-           }
-       }
-      fclose (fdev);
-    }
-  UNBLOCK_INPUT;
-  return build_string (name);
-}
-
-static unsigned long
-procfs_get_total_memory (void)
-{
-  FILE *fmem = NULL;
-  unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
-
-  BLOCK_INPUT;
-  fmem = fopen ("/proc/meminfo", "r");
-
-  if (fmem)
-    {
-      unsigned long entry_value;
-      char entry_name[20];     /* the longest I saw is 13+1 */
-
-      while (!feof (fmem) && !ferror (fmem))
-       {
-         if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value)
-             && strcmp (entry_name, "MemTotal:") == 0)
-           {
-             retval = entry_value;
-             break;
-           }
-       }
-      fclose (fmem);
-    }
-  UNBLOCK_INPUT;
-  return retval;
-}
-
-static Lisp_Object
-procfs_system_process_attributes (pid)
-     Lisp_Object pid;
-{
-  char procfn[PATH_MAX], fn[PATH_MAX];
-  struct stat st;
-  struct passwd *pw;
-  struct group *gr;
-  long clocks_per_sec;
-  char *procfn_end;
-  char procbuf[1025], *p, *q;
-  int fd;
-  ssize_t nread;
-  const char *cmd = NULL;
-  char *cmdline = NULL;
-  size_t cmdsize = 0, cmdline_size;
-  unsigned char c;
-  int proc_id, ppid, uid, gid, pgrp, sess, tty, tpgid, thcount;
-  unsigned long long utime, stime, cutime, cstime, start;
-  long priority, nice, rss;
-  unsigned long minflt, majflt, cminflt, cmajflt, vsize;
-  time_t sec;
-  unsigned usec;
-  EMACS_TIME tnow, tstart, tboot, telapsed,ttotal;
-  double pcpu, pmem;
-  Lisp_Object attrs = Qnil;
-  Lisp_Object cmd_str, decoded_cmd, tem;
-  struct gcpro gcpro1, gcpro2;
-  EMACS_INT uid_eint, gid_eint;
-
-  CHECK_NUMBER_OR_FLOAT (pid);
-  proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
-  sprintf (procfn, "/proc/%lu", proc_id);
-  if (stat (procfn, &st) < 0)
-    return attrs;
-
-  GCPRO2 (attrs, decoded_cmd);
-
-  /* euid egid */
-  uid = st.st_uid;
-  /* Use of EMACS_INT stops GCC whining about limited range of data type.  */
-  uid_eint = uid;
-  attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid_eint)), attrs);
-  BLOCK_INPUT;
-  pw = getpwuid (uid);
-  UNBLOCK_INPUT;
-  if (pw)
-    attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
-
-  gid = st.st_gid;
-  gid_eint = gid;
-  attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid_eint)), attrs);
-  BLOCK_INPUT;
-  gr = getgrgid (gid);
-  UNBLOCK_INPUT;
-  if (gr)
-    attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
-
-  strcpy (fn, procfn);
-  procfn_end = fn + strlen (fn);
-  strcpy (procfn_end, "/stat");
-  fd = emacs_open (fn, O_RDONLY, 0);
-  if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof(procbuf) - 1)) > 0)
-    {
-      procbuf[nread] = '\0';
-      p = procbuf;
-
-      p = strchr (p, '(');
-      if (p != NULL)
-       {
-         q = strrchr (p + 1, ')');
-         /* comm */
-         if (q != NULL)
-           {
-             cmd = p + 1;
-             cmdsize = q - cmd;
-           }
-       }
-      else
-       q = NULL;
-      if (cmd == NULL)
-       {
-         cmd = "???";
-         cmdsize = 3;
-       }
-      /* Command name is encoded in locale-coding-system; decode it.  */
-      cmd_str = make_unibyte_string (cmd, cmdsize);
-      decoded_cmd = code_convert_string_norecord (cmd_str,
-                                                 Vlocale_coding_system, 0);
-      attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
-
-      if (q)
-       {
-         EMACS_INT ppid_eint, pgrp_eint, sess_eint, tpgid_eint, thcount_eint;
-         p = q + 2;
-         /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt utime stime cutime cstime priority nice thcount . start vsize rss */
-         sscanf (p, "%c %d %d %d %d %d %*u %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld",
-                 &c, &ppid, &pgrp, &sess, &tty, &tpgid,
-                 &minflt, &cminflt, &majflt, &cmajflt,
-                 &utime, &stime, &cutime, &cstime,
-                 &priority, &nice, &thcount, &start, &vsize, &rss);
-         {
-           char state_str[2];
-
-           state_str[0] = c;
-           state_str[1] = '\0';
-           tem =  build_string (state_str);
-           attrs = Fcons (Fcons (Qstate, tem), attrs);
-         }
-         /* Stops GCC whining about limited range of data type.  */
-         ppid_eint = ppid;
-         pgrp_eint = pgrp;
-         sess_eint = sess;
-         tpgid_eint = tpgid;
-         thcount_eint = thcount;
-         attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid_eint)), attrs);
-         attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp_eint)), attrs);
-         attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess_eint)), attrs);
-         attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs);
-         attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid_eint)), attrs);
-         attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (minflt)), attrs);
-         attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (majflt)), attrs);
-         attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), attrs);
-         attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), attrs);
-         clocks_per_sec = sysconf (_SC_CLK_TCK);
-         if (clocks_per_sec < 0)
-           clocks_per_sec = 100;
-         attrs = Fcons (Fcons (Qutime,
-                               ltime_from_jiffies (utime, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qstime,
-                               ltime_from_jiffies (stime, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qcutime,
-                               ltime_from_jiffies (cutime, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qcstime,
-                               ltime_from_jiffies (cstime, clocks_per_sec)),
-                        attrs);
-         attrs = Fcons (Fcons (Qpri, make_number (priority)), attrs);
-         attrs = Fcons (Fcons (Qnice, make_number (nice)), attrs);
-         attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs);
-         EMACS_GET_TIME (tnow);
-         get_up_time (&sec, &usec);
-         EMACS_SET_SECS (telapsed, sec);
-         EMACS_SET_USECS (telapsed, usec);
-         EMACS_SUB_TIME (tboot, tnow, telapsed);
-         time_from_jiffies (start, clocks_per_sec, &sec, &usec);
-         EMACS_SET_SECS (tstart, sec);
-         EMACS_SET_USECS (tstart, usec);
-         EMACS_ADD_TIME (tstart, tboot, tstart);
-         attrs = Fcons (Fcons (Qstart,
-                               list3 (make_number
-                                      ((EMACS_SECS (tstart) >> 16) & 0xffff),
-                                      make_number
-                                      (EMACS_SECS (tstart) & 0xffff),
-                                      make_number
-                                      (EMACS_USECS (tstart)))),
-                        attrs);
-         attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs);
-         attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs);
-         EMACS_SUB_TIME (telapsed, tnow, tstart);
-         attrs = Fcons (Fcons (Qetime,
-                               list3 (make_number
-                                      ((EMACS_SECS (telapsed) >> 16) & 0xffff),
-                                      make_number
-                                      (EMACS_SECS (telapsed) & 0xffff),
-                                      make_number
-                                      (EMACS_USECS (telapsed)))),
-                        attrs);
-         time_from_jiffies (utime + stime, clocks_per_sec, &sec, &usec);
-         pcpu = (sec + usec / 1000000.0) / (EMACS_SECS (telapsed) + EMACS_USECS (telapsed) / 1000000.0);
-         if (pcpu > 1.0)
-           pcpu = 1.0;
-         attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs);
-         pmem = 4.0 * 100 * rss / procfs_get_total_memory ();
-         if (pmem > 100)
-           pmem = 100;
-         attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs);
-       }
-    }
-  if (fd >= 0)
-    emacs_close (fd);
-
-  /* args */
-  strcpy (procfn_end, "/cmdline");
-  fd = emacs_open (fn, O_RDONLY, 0);
-  if (fd >= 0)
-    {
-      for (cmdline_size = 0; emacs_read (fd, &c, 1) == 1; cmdline_size++)
-       {
-         if (isspace (c) || c == '\\')
-           cmdline_size++;     /* for later quoting, see below */
-       }
-      if (cmdline_size)
-       {
-         cmdline = xmalloc (cmdline_size + 1);
-         lseek (fd, 0L, SEEK_SET);
-         cmdline[0] = '\0';
-         if ((nread = read (fd, cmdline, cmdline_size)) >= 0)
-           cmdline[nread++] = '\0';
-         else
-           {
-             /* Assigning zero to `nread' makes us skip the following
-                two loops, assign zero to cmdline_size, and enter the
-                following `if' clause that handles unknown command
-                lines.  */
-             nread = 0;
-           }
-         /* We don't want trailing null characters.  */
-         for (p = cmdline + nread - 1; p > cmdline && !*p; p--)
-           nread--;
-         for (p = cmdline; p < cmdline + nread; p++)
-           {
-             /* Escape-quote whitespace and backslashes.  */
-             if (isspace (*p) || *p == '\\')
-               {
-                 memmove (p + 1, p, nread - (p - cmdline));
-                 nread++;
-                 *p++ = '\\';
-               }
-             else if (*p == '\0')
-               *p = ' ';
-           }
-         cmdline_size = nread;
-       }
-      if (!cmdline_size)
-       {
-         if (!cmd)
-           cmd = "???";
-         if (!cmdsize)
-           cmdsize = strlen (cmd);
-         cmdline_size = cmdsize + 2;
-         cmdline = xmalloc (cmdline_size + 1);
-         strcpy (cmdline, "[");
-         strcat (strncat (cmdline, cmd, cmdsize), "]");
-       }
-      emacs_close (fd);
-      /* Command line is encoded in locale-coding-system; decode it.  */
-      cmd_str = make_unibyte_string (cmdline, cmdline_size);
-      decoded_cmd = code_convert_string_norecord (cmd_str,
-                                                 Vlocale_coding_system, 0);
-      xfree (cmdline);
-      attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
-    }
-
-  UNGCPRO;
-  return attrs;
-}
-
-#endif /* !HAVE_PROCFS */
-
 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.
@@ -7494,15 +7080,11 @@ See `system-process-attributes' for getting attributes of a process
 given its ID.  */)
     ()
 {
-#ifdef LISTPROC
-  return LISTPROC ();
-#else
-  return Qnil;
-#endif
+  return list_system_processes ();
 }
 
 DEFUN ("system-process-attributes", Fsystem_process_attributes,
-       Ssystem_process_attributeses, 1, 1, 0,
+       Ssystem_process_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
@@ -7537,8 +7119,10 @@ integer or floating point values.
  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)
@@ -7554,11 +7138,7 @@ integer or floating point values.
 
     Lisp_Object pid;
 {
-#ifdef PROCATTR
-  return PROCATTR (pid);
-#else
-  return Qnil;
-#endif
+  return system_process_attributes (pid);
 }
 \f
 void
@@ -7808,10 +7388,14 @@ syms_of_process ()
   staticpro (&Qutime);
   Qstime = intern ("stime");
   staticpro (&Qstime);
+  Qtime = intern ("time");
+  staticpro (&Qtime);
   Qcutime = intern ("cutime");
   staticpro (&Qcutime);
   Qcstime = intern ("cstime");
   staticpro (&Qcstime);
+  Qctime = intern ("ctime");
+  staticpro (&Qctime);
   Qpri = intern ("pri");
   staticpro (&Qpri);
   Qnice = intern ("nice");
@@ -7928,7 +7512,7 @@ The variable takes effect when `start-process' is called.  */);
   defsubr (&Sset_process_filter_multibyte);
   defsubr (&Sprocess_filter_multibyte_p);
   defsubr (&Slist_system_processes);
-  defsubr (&Ssystem_process_attributeses);
+  defsubr (&Ssystem_process_attributes);
 }
 
 \f
@@ -7957,6 +7541,11 @@ extern int timers_run;
 
 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:
 
    Wait for timeout to elapse and/or keyboard input to be available.
@@ -8226,11 +7815,11 @@ See `system-process-attributes' for getting attributes of a process
 given its ID.  */)
     ()
 {
-  return Qnil;
+  return list_system_processes ();
 }
 
 DEFUN ("system-process-attributes", Fsystem_process_attributes,
-       Ssystem_process_attributeses, 1, 1, 0,
+       Ssystem_process_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
@@ -8265,8 +7854,10 @@ integer or floating point values.
  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)
@@ -8282,7 +7873,7 @@ integer or floating point values.
 
     Lisp_Object pid;
 {
-  return Qnil;
+  return system_process_attributes (pid);
 }
 
 void
@@ -8297,11 +7888,77 @@ syms_of_process ()
   staticpro (&QCtype);
   QCname = intern (":name");
   staticpro (&QCname);
+  QCtype = intern (":type");
+  staticpro (&QCtype);
+  QCname = intern (":name");
+  staticpro (&QCname);
+  Qeuid = intern ("euid");
+  staticpro (&Qeuid);
+  Qegid = intern ("egid");
+  staticpro (&Qegid);
+  Quser = intern ("user");
+  staticpro (&Quser);
+  Qgroup = intern ("group");
+  staticpro (&Qgroup);
+  Qcomm = intern ("comm");
+  staticpro (&Qcomm);
+  Qstate = intern ("state");
+  staticpro (&Qstate);
+  Qppid = intern ("ppid");
+  staticpro (&Qppid);
+  Qpgrp = intern ("pgrp");
+  staticpro (&Qpgrp);
+  Qsess = intern ("sess");
+  staticpro (&Qsess);
+  Qttname = intern ("ttname");
+  staticpro (&Qttname);
+  Qtpgid = intern ("tpgid");
+  staticpro (&Qtpgid);
+  Qminflt = intern ("minflt");
+  staticpro (&Qminflt);
+  Qmajflt = intern ("majflt");
+  staticpro (&Qmajflt);
+  Qcminflt = intern ("cminflt");
+  staticpro (&Qcminflt);
+  Qcmajflt = intern ("cmajflt");
+  staticpro (&Qcmajflt);
+  Qutime = intern ("utime");
+  staticpro (&Qutime);
+  Qstime = intern ("stime");
+  staticpro (&Qstime);
+  Qtime = intern ("time");
+  staticpro (&Qtime);
+  Qcutime = intern ("cutime");
+  staticpro (&Qcutime);
+  Qcstime = intern ("cstime");
+  staticpro (&Qcstime);
+  Qctime = intern ("ctime");
+  staticpro (&Qctime);
+  Qpri = intern ("pri");
+  staticpro (&Qpri);
+  Qnice = intern ("nice");
+  staticpro (&Qnice);
+  Qthcount = intern ("thcount");
+  staticpro (&Qthcount);
+  Qstart = intern ("start");
+  staticpro (&Qstart);
+  Qvsize = intern ("vsize");
+  staticpro (&Qvsize);
+  Qrss = intern ("rss");
+  staticpro (&Qrss);
+  Qetime = intern ("etime");
+  staticpro (&Qetime);
+  Qpcpu = intern ("pcpu");
+  staticpro (&Qpcpu);
+  Qpmem = intern ("pmem");
+  staticpro (&Qpmem);
+  Qargs = intern ("args");
+  staticpro (&Qargs);
 
   defsubr (&Sget_buffer_process);
   defsubr (&Sprocess_inherit_coding_system_flag);
   defsubr (&Slist_system_processes);
-  defsubr (&Ssystem_process_attributeses);
+  defsubr (&Ssystem_process_attributes);
 }
 
 \f