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

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