This source file includes following definitions.
- pcmk__pid_active
- pcmk__read_pidfile
- pcmk__pidfile_matches
- pcmk__lock_pidfile
1
2
3
4
5
6
7
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 pcmk__pid_active(pid_t pid, const char *daemon)
24 {
25 static pid_t last_asked_pid = 0;
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
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;
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;
61
62 } else if ((rc == 0) && no_name_check) {
63 return pcmk_rc_ok;
64
65 } else if (daemon != NULL) {
66
67
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 int rdlnk_errno = errno;
76
77 if (rdlnk_errno != EACCES) {
78 int rc = kill(pid,0);
79
80 if ((rc < 0) && (errno == ESRCH)) {
81 return ESRCH;
82 }
83 }
84 if (last_asked_pid != pid) {
85 if (rdlnk_errno == EACCES) {
86 crm_info("Could not read from %s: %s " CRM_XS " errno=%d",
87 proc_path, strerror(rdlnk_errno), rdlnk_errno);
88 } else {
89 crm_err("Could not read from %s: %s " CRM_XS " errno=%d",
90 proc_path, strerror(rdlnk_errno), rdlnk_errno);
91 }
92 last_asked_pid = pid;
93 }
94 if ((rdlnk_errno == EACCES) && checked_through_kill) {
95
96 return pcmk_rc_ok;
97 } else if (rdlnk_errno == EACCES) {
98 return EACCES;
99 } else {
100 return ESRCH;
101 }
102 }
103 exe_path[rc] = '\0';
104
105 if (daemon[0] != '/') {
106 rc = snprintf(myexe_path, sizeof(myexe_path), CRM_DAEMON_DIR"/%s",
107 daemon);
108 } else {
109 rc = snprintf(myexe_path, sizeof(myexe_path), "%s", daemon);
110 }
111
112 if (rc > 0 && rc < sizeof(myexe_path) && !strcmp(exe_path, myexe_path)) {
113 return pcmk_rc_ok;
114 }
115 }
116
117 return ESRCH;
118 }
119
120 #define LOCKSTRLEN 11
121
122
123
124
125
126
127
128
129
130
131 int
132 pcmk__read_pidfile(const char *filename, pid_t *pid)
133 {
134 int fd;
135 struct stat sbuf;
136 int rc = pcmk_rc_unknown_format;
137 long long pid_read = 0;
138 char buf[LOCKSTRLEN + 1];
139
140 CRM_CHECK((filename != NULL) && (pid != NULL), return EINVAL);
141
142 fd = open(filename, O_RDONLY);
143 if (fd < 0) {
144 return errno;
145 }
146
147 if ((fstat(fd, &sbuf) >= 0) && (sbuf.st_size < LOCKSTRLEN)) {
148 sleep(2);
149
150
151 }
152
153 if (read(fd, buf, sizeof(buf)) < 1) {
154 rc = errno;
155 goto bail;
156 }
157
158 if (sscanf(buf, "%lld", &pid_read) > 0) {
159 if (pid_read <= 0) {
160 rc = ESRCH;
161 } else {
162 rc = pcmk_rc_ok;
163 *pid = (pid_t) pid_read;
164 crm_trace("Read pid %lld from %s", pid_read, filename);
165 }
166 }
167
168 bail:
169 close(fd);
170 return rc;
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184
185 int
186 pcmk__pidfile_matches(const char *filename, pid_t expected_pid,
187 const char *expected_name, pid_t *pid)
188 {
189 pid_t pidfile_pid = 0;
190 int rc = pcmk__read_pidfile(filename, &pidfile_pid);
191
192 if (pid) {
193 *pid = pidfile_pid;
194 }
195
196 if (rc != pcmk_rc_ok) {
197
198 unlink(filename);
199 rc = ENOENT;
200
201 } else if ((expected_pid > 0) && (pidfile_pid == expected_pid)) {
202
203 rc = pcmk_rc_ok;
204
205 } else if (pcmk__pid_active(pidfile_pid, expected_name) == ESRCH) {
206
207 unlink(filename);
208 rc = ENOENT;
209
210 } else if ((expected_pid > 0) && (pidfile_pid != expected_pid)) {
211
212 rc = EEXIST;
213 }
214
215 return rc;
216 }
217
218
219
220
221
222
223
224
225
226
227 int
228 pcmk__lock_pidfile(const char *filename, const char *name)
229 {
230 pid_t mypid = getpid();
231 int fd = 0;
232 int rc = 0;
233 char buf[LOCKSTRLEN + 2];
234
235 rc = pcmk__pidfile_matches(filename, 0, name, NULL);
236 if ((rc != pcmk_rc_ok) && (rc != ENOENT)) {
237
238 return rc;
239 }
240
241 fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644);
242 if (fd < 0) {
243 return errno;
244 }
245
246 snprintf(buf, sizeof(buf), "%*lld\n", LOCKSTRLEN - 1, (long long) mypid);
247 rc = write(fd, buf, LOCKSTRLEN);
248 close(fd);
249
250 if (rc != LOCKSTRLEN) {
251 crm_perror(LOG_ERR, "Incomplete write to %s", filename);
252 return errno;
253 }
254
255 rc = pcmk__pidfile_matches(filename, mypid, name, NULL);
256 if (rc != pcmk_rc_ok) {
257
258 unlink(filename);
259 }
260 return rc;
261 }