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

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