root/lib/common/pid.c

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

DEFINITIONS

This source file includes following definitions.
  1. pcmk__pid_active
  2. pcmk__read_pidfile
  3. pcmk__pidfile_matches
  4. pcmk__lock_pidfile

   1 /*
   2  * Copyright 2004-2022 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #ifndef _GNU_SOURCE
  13 #  define _GNU_SOURCE
  14 #endif
  15 
  16 #include <stdio.h>
  17 #include <string.h>
  18 #include <sys/stat.h>
  19 
  20 #include <crm/crm.h>
  21 
  22 int
  23 pcmk__pid_active(pid_t pid, const char *daemon)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25     static pid_t last_asked_pid = 0;  /* log spam prevention */
  26     int rc = 0;
  27 
  28     if (pid <= 0) {
  29         return EINVAL;
  30     }
  31 
  32     rc = kill(pid, 0);
  33     if ((rc < 0) && (errno == ESRCH)) {
  34         return ESRCH;  /* no such PID detected */
  35 
  36     } else if ((daemon == NULL) || !pcmk__procfs_has_pids()) {
  37         // The kill result is all we have, we can't check the name
  38 
  39         if (rc == 0) {
  40             return pcmk_rc_ok;
  41         }
  42         rc = errno;
  43         if (last_asked_pid != pid) {
  44             crm_info("Cannot examine PID %lld: %s",
  45                      (long long) pid, pcmk_rc_str(rc));
  46             last_asked_pid = pid;
  47         }
  48         return rc; /* errno != ESRCH */
  49 
  50     } else {
  51         /* make sure PID hasn't been reused by another process
  52            XXX: might still be just a zombie, which could confuse decisions */
  53         bool checked_through_kill = (rc == 0);
  54         char exe_path[PATH_MAX], myexe_path[PATH_MAX];
  55 
  56         rc = pcmk__procfs_pid2path(pid, exe_path, sizeof(exe_path));
  57         if (rc != pcmk_rc_ok) {
  58             if (rc != EACCES) {
  59                 // Check again to filter out races
  60                 if ((kill(pid, 0) < 0) && (errno == ESRCH)) {
  61                     return ESRCH;
  62                 }
  63             }
  64             if (last_asked_pid != pid) {
  65                 if (rc == EACCES) {
  66                     crm_info("Could not get executable for PID %lld: %s "
  67                              CRM_XS " rc=%d",
  68                              (long long) pid, pcmk_rc_str(rc), rc);
  69                 } else {
  70                     crm_err("Could not get executable for PID %lld: %s "
  71                             CRM_XS " rc=%d",
  72                             (long long) pid, pcmk_rc_str(rc), rc);
  73                 }
  74                 last_asked_pid = pid;
  75             }
  76             if (rc == EACCES) {
  77                 // Trust kill if it was OK (we can't double-check via path)
  78                 return checked_through_kill? pcmk_rc_ok : EACCES;
  79             } else {
  80                 return ESRCH;  /* most likely errno == ENOENT */
  81             }
  82         }
  83 
  84         if (daemon[0] != '/') {
  85             rc = snprintf(myexe_path, sizeof(myexe_path), CRM_DAEMON_DIR"/%s",
  86                           daemon);
  87         } else {
  88             rc = snprintf(myexe_path, sizeof(myexe_path), "%s", daemon);
  89         }
  90 
  91         if (rc > 0 && rc < sizeof(myexe_path) && !strcmp(exe_path, myexe_path)) {
  92             return pcmk_rc_ok;
  93         }
  94     }
  95 
  96     return ESRCH;
  97 }
  98 
  99 #define LOCKSTRLEN      11
 100 
 101 /*!
 102  * \internal
 103  * \brief Read a process ID from a file
 104  *
 105  * \param[in]  filename  Process ID file to read
 106  * \param[out] pid       Where to put PID that was read
 107  *
 108  * \return Standard Pacemaker return code
 109  */
 110 int
 111 pcmk__read_pidfile(const char *filename, pid_t *pid)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113     int fd;
 114     struct stat sbuf;
 115     int rc = pcmk_rc_unknown_format;
 116     long long pid_read = 0;
 117     char buf[LOCKSTRLEN + 1];
 118 
 119     CRM_CHECK((filename != NULL) && (pid != NULL), return EINVAL);
 120 
 121     fd = open(filename, O_RDONLY);
 122     if (fd < 0) {
 123         return errno;
 124     }
 125 
 126     if ((fstat(fd, &sbuf) >= 0) && (sbuf.st_size < LOCKSTRLEN)) {
 127         sleep(2);           /* if someone was about to create one,
 128                              * give'm a sec to do so
 129                              */
 130     }
 131 
 132     if (read(fd, buf, sizeof(buf)) < 1) {
 133         rc = errno;
 134         goto bail;
 135     }
 136 
 137     if (sscanf(buf, "%lld", &pid_read) > 0) {
 138         if (pid_read <= 0) {
 139             rc = ESRCH;
 140         } else {
 141             rc = pcmk_rc_ok;
 142             *pid = (pid_t) pid_read;
 143             crm_trace("Read pid %lld from %s", pid_read, filename);
 144         }
 145     }
 146 
 147   bail:
 148     close(fd);
 149     return rc;
 150 }
 151 
 152 /*!
 153  * \internal
 154  * \brief Check whether a process from a PID file matches expected values
 155  *
 156  * \param[in]  filename       Path of PID file
 157  * \param[in]  expected_pid   If positive, compare to this PID
 158  * \param[in]  expected_name  If not NULL, the PID from the PID file is valid
 159  *                            only if it is active as a process with this name
 160  * \param[out] pid            If not NULL, store PID found in PID file here
 161  *
 162  * \return Standard Pacemaker return code
 163  */
 164 int
 165 pcmk__pidfile_matches(const char *filename, pid_t expected_pid,
     /* [previous][next][first][last][top][bottom][index][help] */
 166                       const char *expected_name, pid_t *pid)
 167 {
 168     pid_t pidfile_pid = 0;
 169     int rc = pcmk__read_pidfile(filename, &pidfile_pid);
 170 
 171     if (pid) {
 172         *pid = pidfile_pid;
 173     }
 174 
 175     if (rc != pcmk_rc_ok) {
 176         // Error reading PID file or invalid contents
 177         unlink(filename);
 178         rc = ENOENT;
 179 
 180     } else if ((expected_pid > 0) && (pidfile_pid == expected_pid)) {
 181         // PID in file matches what was expected
 182         rc = pcmk_rc_ok;
 183 
 184     } else if (pcmk__pid_active(pidfile_pid, expected_name) == ESRCH) {
 185         // Contains a stale value
 186         unlink(filename);
 187         rc = ENOENT;
 188 
 189     } else if ((expected_pid > 0) && (pidfile_pid != expected_pid)) {
 190         // Locked by existing process
 191         rc = EEXIST;
 192     }
 193 
 194     return rc;
 195 }
 196 
 197 /*!
 198  * \internal
 199  * \brief Create a PID file for the current process (if not already existent)
 200  *
 201  * \param[in] filename   Name of PID file to create
 202  * \param[in] name       Name of current process
 203  *
 204  * \return Standard Pacemaker return code
 205  */
 206 int
 207 pcmk__lock_pidfile(const char *filename, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 208 {
 209     pid_t mypid = getpid();
 210     int fd = 0;
 211     int rc = 0;
 212     char buf[LOCKSTRLEN + 2];
 213 
 214     rc = pcmk__pidfile_matches(filename, 0, name, NULL);
 215     if ((rc != pcmk_rc_ok) && (rc != ENOENT)) {
 216         // Locked by existing process
 217         return rc;
 218     }
 219 
 220     fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644);
 221     if (fd < 0) {
 222         return errno;
 223     }
 224 
 225     snprintf(buf, sizeof(buf), "%*lld\n", LOCKSTRLEN - 1, (long long) mypid);
 226     rc = write(fd, buf, LOCKSTRLEN);
 227     close(fd);
 228 
 229     if (rc != LOCKSTRLEN) {
 230         crm_perror(LOG_ERR, "Incomplete write to %s", filename);
 231         return errno;
 232     }
 233 
 234     rc = pcmk__pidfile_matches(filename, mypid, name, NULL);
 235     if (rc != pcmk_rc_ok) {
 236         // Something is really wrong -- maybe I/O error on read back?
 237         unlink(filename);
 238     }
 239     return rc;
 240 }

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