pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
pid.c
Go to the documentation of this file.
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
22int
23pcmk__pid_active(pid_t pid, const char *daemon)
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
110int
111pcmk__read_pidfile(const char *filename, pid_t *pid)
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
164int
165pcmk__pidfile_matches(const char *filename, pid_t expected_pid,
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
206int
207pcmk__lock_pidfile(const char *filename, const char *name)
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}
const char * name
Definition: cib.c:24
bool pcmk__procfs_has_pids(void)
Definition: procfs.c:211
int pcmk__procfs_pid2path(pid_t pid, char path[], size_t path_size)
Definition: procfs.c:179
#define CRM_DAEMON_DIR
Definition: config.h:24
uint32_t pid
Definition: cpg.c:1
A dumping ground.
#define crm_info(fmt, args...)
Definition: logging.h:362
#define CRM_XS
Definition: logging.h:55
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:310
#define CRM_CHECK(expr, failure_action)
Definition: logging.h:227
#define crm_err(fmt, args...)
Definition: logging.h:359
#define crm_trace(fmt, args...)
Definition: logging.h:365
int pcmk__read_pidfile(const char *filename, pid_t *pid)
Definition: pid.c:111
int pcmk__pid_active(pid_t pid, const char *daemon)
Definition: pid.c:23
#define LOCKSTRLEN
Definition: pid.c:99
int pcmk__pidfile_matches(const char *filename, pid_t expected_pid, const char *expected_name, pid_t *pid)
Definition: pid.c:165
int pcmk__lock_pidfile(const char *filename, const char *name)
Definition: pid.c:207
int daemon(int nochdir, int noclose)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
Definition: results.c:476
@ pcmk_rc_ok
Definition: results.h:148
@ pcmk_rc_unknown_format
Definition: results.h:142