pacemaker 2.1.1-77db578727
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
pid.c
Go to the documentation of this file.
1/*
2 * Copyright 2004-2020 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#if SUPPORT_PROCFS
27 static int have_proc_pid = 0;
28#else
29 static int have_proc_pid = -1;
30#endif
31 int rc = 0;
32 bool no_name_check = ((daemon == NULL) || (have_proc_pid == -1));
33
34 if (have_proc_pid == 0) {
35 /* evaluation of /proc/PID/exe applicability via self-introspection */
36 char proc_path[PATH_MAX], exe_path[PATH_MAX];
37 snprintf(proc_path, sizeof(proc_path), "/proc/%lld/exe",
38 (long long) getpid());
39 have_proc_pid = 1;
40 if (readlink(proc_path, exe_path, sizeof(exe_path) - 1) < 0) {
41 have_proc_pid = -1;
42 }
43 }
44
45 if (pid <= 0) {
46 return EINVAL;
47 }
48
49 rc = kill(pid, 0);
50 if ((rc < 0) && (errno == ESRCH)) {
51 return ESRCH; /* no such PID detected */
52
53 } else if ((rc < 0) && no_name_check) {
54 rc = errno;
55 if (last_asked_pid != pid) {
56 crm_info("Cannot examine PID %lld: %s",
57 (long long) pid, strerror(errno));
58 last_asked_pid = pid;
59 }
60 return rc; /* errno != ESRCH */
61
62 } else if ((rc == 0) && no_name_check) {
63 return pcmk_rc_ok; /* kill as the only indicator, cannot double check */
64
65 } else if (daemon != NULL) {
66 /* make sure PID hasn't been reused by another process
67 XXX: might still be just a zombie, which could confuse decisions */
68 bool checked_through_kill = (rc == 0);
69 char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX];
70 snprintf(proc_path, sizeof(proc_path), "/proc/%lld/exe",
71 (long long) pid);
72
73 rc = readlink(proc_path, exe_path, sizeof(exe_path) - 1);
74 if (rc < 0) {
75 if (last_asked_pid != pid) {
76 if (errno == EACCES) {
77 crm_info("Could not read from %s: %s " CRM_XS " errno=%d",
78 proc_path, strerror(errno), errno);
79 } else {
80 crm_err("Could not read from %s: %s " CRM_XS " errno=%d",
81 proc_path, strerror(errno), errno);
82 }
83 last_asked_pid = pid;
84 }
85 if ((errno == EACCES) && checked_through_kill) {
86 // Trust kill result, can't double-check via path
87 return pcmk_rc_ok;
88 } else if (errno == EACCES) {
89 return EACCES;
90 } else {
91 return ESRCH; /* most likely errno == ENOENT */
92 }
93 }
94 exe_path[rc] = '\0';
95
96 if (daemon[0] != '/') {
97 rc = snprintf(myexe_path, sizeof(myexe_path), CRM_DAEMON_DIR"/%s",
98 daemon);
99 } else {
100 rc = snprintf(myexe_path, sizeof(myexe_path), "%s", daemon);
101 }
102
103 if (rc > 0 && rc < sizeof(myexe_path) && !strcmp(exe_path, myexe_path)) {
104 return pcmk_rc_ok;
105 }
106 }
107
108 return ESRCH;
109}
110
111#define LOCKSTRLEN 11
112
122int
123pcmk__read_pidfile(const char *filename, pid_t *pid)
124{
125 int fd;
126 struct stat sbuf;
128 long long pid_read = 0;
129 char buf[LOCKSTRLEN + 1];
130
131 CRM_CHECK((filename != NULL) && (pid != NULL), return EINVAL);
132
133 fd = open(filename, O_RDONLY);
134 if (fd < 0) {
135 return errno;
136 }
137
138 if ((fstat(fd, &sbuf) >= 0) && (sbuf.st_size < LOCKSTRLEN)) {
139 sleep(2); /* if someone was about to create one,
140 * give'm a sec to do so
141 */
142 }
143
144 if (read(fd, buf, sizeof(buf)) < 1) {
145 rc = errno;
146 goto bail;
147 }
148
149 if (sscanf(buf, "%lld", &pid_read) > 0) {
150 if (pid_read <= 0) {
151 rc = ESRCH;
152 } else {
153 rc = pcmk_rc_ok;
154 *pid = (pid_t) pid_read;
155 crm_trace("Read pid %lld from %s", pid_read, filename);
156 }
157 }
158
159 bail:
160 close(fd);
161 return rc;
162}
163
176int
177pcmk__pidfile_matches(const char *filename, pid_t expected_pid,
178 const char *expected_name, pid_t *pid)
179{
180 pid_t pidfile_pid = 0;
181 int rc = pcmk__read_pidfile(filename, &pidfile_pid);
182
183 if (pid) {
184 *pid = pidfile_pid;
185 }
186
187 if (rc != pcmk_rc_ok) {
188 // Error reading PID file or invalid contents
189 unlink(filename);
190 rc = ENOENT;
191
192 } else if ((expected_pid > 0) && (pidfile_pid == expected_pid)) {
193 // PID in file matches what was expected
194 rc = pcmk_rc_ok;
195
196 } else if (pcmk__pid_active(pidfile_pid, expected_name) == ESRCH) {
197 // Contains a stale value
198 unlink(filename);
199 rc = ENOENT;
200
201 } else if ((expected_pid > 0) && (pidfile_pid != expected_pid)) {
202 // Locked by existing process
203 rc = EEXIST;
204 }
205
206 return rc;
207}
208
218int
219pcmk__lock_pidfile(const char *filename, const char *name)
220{
221 pid_t mypid = getpid();
222 int fd = 0;
223 int rc = 0;
224 char buf[LOCKSTRLEN + 2];
225
226 rc = pcmk__pidfile_matches(filename, 0, name, NULL);
227 if ((rc != pcmk_rc_ok) && (rc != ENOENT)) {
228 // Locked by existing process
229 return rc;
230 }
231
232 fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644);
233 if (fd < 0) {
234 return errno;
235 }
236
237 snprintf(buf, sizeof(buf), "%*lld\n", LOCKSTRLEN - 1, (long long) mypid);
238 rc = write(fd, buf, LOCKSTRLEN);
239 close(fd);
240
241 if (rc != LOCKSTRLEN) {
242 crm_perror(LOG_ERR, "Incomplete write to %s", filename);
243 return errno;
244 }
245
246 rc = pcmk__pidfile_matches(filename, mypid, name, NULL);
247 if (rc != pcmk_rc_ok) {
248 // Something is really wrong -- maybe I/O error on read back?
249 unlink(filename);
250 }
251 return rc;
252}
#define CRM_DAEMON_DIR
Definition config.h:26
uint32_t pid
Definition cpg.c:1
A dumping ground.
#define crm_info(fmt, args...)
Definition logging.h:353
#define CRM_XS
Definition logging.h:54
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition logging.h:301
#define CRM_CHECK(expr, failure_action)
Definition logging.h:218
#define crm_err(fmt, args...)
Definition logging.h:350
#define crm_trace(fmt, args...)
Definition logging.h:356
char * name
Definition pcmk_fence.c:31
int rc
Definition pcmk_fence.c:35
int pcmk__read_pidfile(const char *filename, pid_t *pid)
Definition pid.c:123
int pcmk__pid_active(pid_t pid, const char *daemon)
Definition pid.c:23
#define LOCKSTRLEN
Definition pid.c:111
int pcmk__pidfile_matches(const char *filename, pid_t expected_pid, const char *expected_name, pid_t *pid)
Definition pid.c:177
int pcmk__lock_pidfile(const char *filename, const char *name)
Definition pid.c:219
char * strerror(int errnum)
int daemon(int nochdir, int noclose)
@ pcmk_rc_ok
Definition results.h:142
@ pcmk_rc_unknown_format
Definition results.h:136