pacemaker 3.0.1-16e74fc4da
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pid.c
Go to the documentation of this file.
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
18int
19pcmk__pid_active(pid_t pid, const char *daemon)
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
106int
107pcmk__read_pidfile(const char *filename, pid_t *pid)
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
167int
168pcmk__pidfile_matches(const char *filename, pid_t expected_pid,
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
209int
210pcmk__lock_pidfile(const char *filename, const char *name)
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}
const char * name
Definition cib.c:26
bool pcmk__procfs_has_pids(void)
Definition procfs.c:235
int pcmk__procfs_pid2path(pid_t pid, char path[], size_t path_size)
Definition procfs.c:203
#define CRM_DAEMON_DIR
Definition config.h:21
uint32_t pid
Definition cpg.c:1
A dumping ground.
#define crm_info(fmt, args...)
Definition logging.h:365
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:299
#define CRM_CHECK(expr, failure_action)
Definition logging.h:213
#define crm_err(fmt, args...)
Definition logging.h:357
#define crm_trace(fmt, args...)
Definition logging.h:370
int pcmk__read_pidfile(const char *filename, pid_t *pid)
Definition pid.c:107
int pcmk__pid_active(pid_t pid, const char *daemon)
Definition pid.c:19
#define LOCKSTRLEN
Definition pid.c:95
int pcmk__pidfile_matches(const char *filename, pid_t expected_pid, const char *expected_name, pid_t *pid)
Definition pid.c:168
int pcmk__lock_pidfile(const char *filename, const char *name)
Definition pid.c:210
#define ENODATA
Definition portability.h:61
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition results.c:617
@ pcmk_rc_ok
Definition results.h:159