root/maint/gnulib/lib/get_ppid_of.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_ppid_of
  2. main

   1 /* Determine the parent process of a given process.
   2    Copyright (C) 2019-2021 Free Software Foundation, Inc.
   3    Written by Bruno Haible <bruno@clisp.org>, 2019.
   4 
   5    This file is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU Lesser General Public License as
   7    published by the Free Software Foundation; either version 3 of the
   8    License, or (at your option) any later version.
   9 
  10    This file is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU Lesser General Public License for more details.
  14 
  15    You should have received a copy of the GNU Lesser General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 #include <config.h>
  19 
  20 /* Specification.  */
  21 #include "get_ppid_of.h"
  22 
  23 #include <stdio.h>
  24 #include <string.h>
  25 
  26 #if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) || defined __GNU__ || defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ || defined __minix || defined __sun /* Linux, GNU/kFreeBSD, GNU/Hurd, FreeBSD, NetBSD, Minix, Solaris */
  27 # include <fcntl.h>
  28 # include <unistd.h>
  29 #endif
  30 
  31 #if defined __OpenBSD__                                     /* OpenBSD */
  32 # include <sys/sysctl.h> /* sysctl, struct kinfo_proc */
  33 #endif
  34 
  35 #if defined __APPLE__ && defined __MACH__                   /* Mac OS X */
  36 # include <libproc.h>
  37 #endif
  38 
  39 #if defined _AIX                                            /* AIX */
  40 # include <procinfo.h>
  41 #endif
  42 
  43 #if defined __hpux                                          /* HP-UX */
  44 # include <unistd.h>
  45 # include <sys/param.h>
  46 # include <sys/pstat.h>
  47 #endif
  48 
  49 #if defined __sgi                                           /* IRIX */
  50 # include <unistd.h>
  51 # include <fcntl.h>
  52 # include <sys/procfs.h>
  53 #endif
  54 
  55 #if defined __CYGWIN__                                      /* Cygwin */
  56 # define WIN32_LEAN_AND_MEAN
  57 # include <windows.h> /* needed to get 'struct external_pinfo' defined */
  58 # include <sys/cygwin.h>
  59 #endif
  60 
  61 #if defined __BEOS__ || defined __HAIKU__                   /* BeOS, Haiku */
  62 # include <unistd.h>
  63 #endif
  64 
  65 pid_t
  66 get_ppid_of (pid_t pid)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68 #if defined __linux__ || defined __ANDROID__ || (defined __FreeBSD_kernel__ && !defined __FreeBSD__) || defined __GNU__ /* Linux, GNU/kFreeBSD, GNU/Hurd */
  69 /* GNU/kFreeBSD mounts /proc as linprocfs, which looks like a Linux /proc
  70    file system.  */
  71 
  72   /* Read the contents of /proc/<pid>/status into memory.  */
  73   char filename[6 + 10 + 7 + 1];
  74   int fd;
  75 
  76   sprintf (filename, "/proc/%u/status", (unsigned int) pid);
  77   fd = open (filename, O_RDONLY | O_CLOEXEC);
  78   if (fd >= 0)
  79     {
  80       char buf[4096 + 1];
  81       ssize_t nread = read (fd, buf, sizeof (buf) - 1);
  82       close (fd);
  83       if (nread >= 0)
  84         {
  85           char *bufend = buf + nread;
  86           char *p;
  87 
  88           /* NUL-terminate the buffer.  */
  89           *bufend = '\0';
  90 
  91           /* Search for a line that starts with "PPid:".  */
  92           for (p = buf;;)
  93             {
  94               if (bufend - p >= 5 && memcmp (p, "PPid:", 5) == 0)
  95                 {
  96                   unsigned int ppid = 0;
  97                   if (sscanf (p + 5, "%u", &ppid) > 0)
  98                     return ppid;
  99                 }
 100               p = strchr (p, '\n');
 101               if (p != NULL)
 102                 p++;
 103               else
 104                 break;
 105             }
 106         }
 107     }
 108 
 109 #endif
 110 
 111 #if defined __FreeBSD__ || defined __DragonFly__ || defined __NetBSD__ /* FreeBSD, NetBSD */
 112 
 113   /* Read the contents of /proc/<pid>/status into memory.  */
 114   char filename[6 + 10 + 7 + 1];
 115   int fd;
 116 
 117   sprintf (filename, "/proc/%u/status", (unsigned int) pid);
 118   fd = open (filename, O_RDONLY | O_CLOEXEC);
 119   if (fd >= 0)
 120     {
 121       char buf[4096 + 1];
 122       ssize_t nread = read (fd, buf, sizeof (buf) - 1);
 123       close (fd);
 124       if (nread >= 0)
 125         {
 126           char *p;
 127 
 128           /* NUL-terminate the buffer.  */
 129           buf[nread] = '\0';
 130 
 131           /* Search for the third space-separated field.  */
 132           p = strchr (buf, ' ');
 133           if (p != NULL)
 134             {
 135               p = strchr (p + 1, ' ');
 136               if (p != NULL)
 137                 {
 138                   unsigned int ppid = 0;
 139                   if (sscanf (p + 1, "%u", &ppid) > 0)
 140                     return ppid;
 141                 }
 142             }
 143         }
 144     }
 145 
 146 #endif
 147 
 148 #if defined __minix                                         /* Minix */
 149 
 150   /* Read the contents of /proc/<pid>/psinfo into memory.  */
 151   char filename[6 + 10 + 7 + 1];
 152   int fd;
 153 
 154   sprintf (filename, "/proc/%u/psinfo", (unsigned int) pid);
 155   fd = open (filename, O_RDONLY | O_CLOEXEC);
 156   if (fd >= 0)
 157     {
 158       char buf[4096 + 1];
 159       ssize_t nread = read (fd, buf, sizeof (buf) - 1);
 160       close (fd);
 161       if (nread >= 0)
 162         {
 163           char *p;
 164           int count;
 165 
 166           /* NUL-terminate the buffer.  */
 167           buf[nread] = '\0';
 168 
 169           /* Search for the 16th space-separated field.  */
 170           p = strchr (buf, ' ');
 171           for (count = 1; p != NULL && count < 15; count++)
 172             p = strchr (p + 1, ' ');
 173           if (p != NULL)
 174             {
 175               unsigned int ppid = 0;
 176               if (sscanf (p + 1, "%u", &ppid) > 0)
 177                 return ppid;
 178             }
 179         }
 180     }
 181 
 182 #endif
 183 
 184 #if defined __sun                                           /* Solaris */
 185 
 186   /* Read the contents of /proc/<pid>/psinfo into memory.
 187      Alternatively, we could read the contents of /proc/<pid>/status into
 188      memory.  But it contains a lot of information that we don't need.  */
 189   char filename[6 + 10 + 7 + 1];
 190   int fd;
 191 
 192   sprintf (filename, "/proc/%u/psinfo", (unsigned int) pid);
 193   fd = open (filename, O_RDONLY | O_CLOEXEC);
 194   if (fd >= 0)
 195     {
 196       /* The contents is a 'struct psinfo'.  But since 'struct psinfo'
 197          has a different size in a 32-bit and a 64-bit environment, we
 198          avoid it.  Nevertheless, the size of this contents depends on
 199          whether the process that reads it is 32-bit or 64-bit!  */
 200       #if defined __LP64__
 201       # define PSINFO_SIZE 416
 202       #else
 203       # define PSINFO_SIZE 336
 204       #endif
 205       union { char all[PSINFO_SIZE]; unsigned int header[11]; } buf;
 206       ssize_t nread = read (fd, buf.all, sizeof (buf.all));
 207       close (fd);
 208       if (nread >= (ssize_t) sizeof (buf.header))
 209         return buf.header[3];
 210     }
 211 
 212 #endif
 213 
 214 #if defined __OpenBSD__                                     /* OpenBSD */
 215 
 216   /* Documentation: https://man.openbsd.org/sysctl.2  */
 217   int info_path[] =
 218     { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid, sizeof (struct kinfo_proc), 1 };
 219   struct kinfo_proc info;
 220   size_t len;
 221 
 222   len = sizeof (info);
 223   if (sysctl (info_path, 6, &info, &len, NULL, 0) >= 0 && len == sizeof (info))
 224     return info.p_ppid;
 225 
 226 #endif
 227 
 228 #if defined __APPLE__ && defined __MACH__                   /* Mac OS X */
 229 
 230 # if defined PROC_PIDT_SHORTBSDINFO
 231   struct proc_bsdshortinfo info;
 232 
 233   if (proc_pidinfo (pid, PROC_PIDT_SHORTBSDINFO, 0, &info, sizeof (info))
 234       == sizeof (info))
 235     return info.pbsi_ppid;
 236 # else
 237   /* Note: The second part of 'struct proc_bsdinfo' differs in size between
 238      32-bit and 64-bit environments, and the kernel of Mac OS X 10.5 knows
 239      only about the 32-bit 'struct proc_bsdinfo'.  Fortunately all the info
 240      we need is in the first part, which is the same in 32-bit and 64-bit.  */
 241   struct proc_bsdinfo info;
 242 
 243   if (proc_pidinfo (pid, PROC_PIDTBSDINFO, 0, &info, 128) == 128)
 244     return info.pbi_ppid;
 245 # endif
 246 
 247 #endif
 248 
 249 #if defined _AIX                                            /* AIX */
 250 
 251   /* Reference: https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.basetrf1/getprocs.htm
 252   */
 253   struct procentry64 procs;
 254   if (getprocs64 (&procs, sizeof procs, NULL, 0, &pid, 1) > 0)
 255     return procs.pi_ppid;
 256 
 257 #endif
 258 
 259 #if defined __hpux                                          /* HP-UX */
 260 
 261   struct pst_status status;
 262   if (pstat_getproc (&status, sizeof status, 0, pid) > 0)
 263     return status.pst_ppid;
 264   else
 265     {
 266 # if !defined __LP64__
 267       /* Support for 32-bit programs running in 64-bit HP-UX.
 268          The documented way to do this is to use the same source code
 269          as above, but in a compilation unit where '#define _PSTAT64 1'
 270          is in effect.  I prefer a single compilation unit; the struct
 271          size and the offsets are not going to change.  */
 272       char status64[1216];
 273       if (__pstat_getproc64 (status64, sizeof status64, 0, pid) > 0)
 274         return *(unsigned long long *)(status64 + 24);
 275 # endif
 276     }
 277 
 278 #endif
 279 
 280 #if defined __sgi                                           /* IRIX */
 281 
 282   char filename[12 + 10 + 1];
 283   int fd;
 284 
 285   sprintf (filename, "/proc/pinfo/%u", pid);
 286   fd = open (filename, O_RDONLY | O_CLOEXEC);
 287   if (0 <= fd)
 288     {
 289       prpsinfo_t buf;
 290       int ioctl_ok = 0 <= ioctl (fd, PIOCPSINFO, &buf);
 291       close (fd);
 292       if (ioctl_ok)
 293         return buf.pr_ppid;
 294     }
 295 
 296 #endif
 297 
 298 #if defined __CYGWIN__                                      /* Cygwin */
 299 
 300   struct external_pinfo *info =
 301     (struct external_pinfo *) cygwin_internal (CW_GETPINFO, pid);
 302   if (info != NULL)
 303     return info->ppid;
 304 
 305 #endif
 306 
 307 #if defined __BEOS__ || defined __HAIKU__                   /* BeOS, Haiku */
 308 
 309   if (pid == getpid ())
 310     return getppid ();
 311 
 312 #endif
 313 
 314   return 0;
 315 }
 316 
 317 #ifdef TEST
 318 
 319 #include <stdlib.h>
 320 #include <unistd.h>
 321 
 322 /* Usage: ./a.out
 323    or:    ./a.out PID
 324  */
 325 int
 326 main (int argc, char *argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
 327 {
 328   char *arg = argv[1];
 329   pid_t pid = (arg != NULL ? atoi (arg) : getpid ());
 330   pid_t parent = get_ppid_of (pid);
 331   printf ("PID=%lu PPID=%lu\n", (unsigned long) pid, (unsigned long) parent);
 332   return 0;
 333 }
 334 
 335 /*
 336  * Local Variables:
 337  * compile-command: "gcc -ggdb -DTEST -Wall -I.. get_ppid_of.c"
 338  * End:
 339  */
 340 
 341 #endif

/* [previous][next][first][last][top][bottom][index][help] */