LCOV - code coverage report
Current view: top level - common - pid.c (source / functions) Hit Total Coverage
Test: Pacemaker code coverage Lines: 0 97 0.0 %
Date: 2024-05-07 11:09:47 Functions: 0 4 0.0 %

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

Generated by: LCOV version 1.14