pacemaker  2.0.1-15814c6c0d
Scalable High-Availability cluster resource manager
pid.c
Go to the documentation of this file.
1 /*
2  * Copyright 2004-2018 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This source code is licensed under the GNU Lesser General Public License
5  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
6  */
7 
8 #include <crm_internal.h>
9 
10 #ifndef _GNU_SOURCE
11 # define _GNU_SOURCE
12 #endif
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <sys/stat.h>
17 
18 #include <crm/crm.h>
19 
20 int
21 crm_pid_active(long pid, const char *daemon)
22 {
23  static int have_proc_pid = 0;
24 
25  if (have_proc_pid == 0) {
26  char proc_path[PATH_MAX], exe_path[PATH_MAX];
27 
28  // Make sure pid hasn't been reused by another process
29  snprintf(proc_path, sizeof(proc_path), "/proc/%lu/exe",
30  (long unsigned int)getpid());
31 
32  have_proc_pid = 1;
33  if (readlink(proc_path, exe_path, PATH_MAX - 1) < 0) {
34  have_proc_pid = -1;
35  }
36  }
37 
38  if (pid <= 0) {
39  return -1;
40 
41  } else if ((kill(pid, 0) < 0) && (errno == ESRCH)) {
42  return 0;
43 
44  } else if ((daemon == NULL) || (have_proc_pid == -1)) {
45  return 1;
46 
47  } else {
48  int rc = 0;
49  char proc_path[PATH_MAX], exe_path[PATH_MAX], myexe_path[PATH_MAX];
50 
51  // Make sure pid hasn't been reused by another process
52  snprintf(proc_path, sizeof(proc_path), "/proc/%ld/exe", pid);
53 
54  rc = readlink(proc_path, exe_path, PATH_MAX - 1);
55  if ((rc < 0) && (errno == EACCES)) {
56  crm_perror(LOG_INFO, "Could not read from %s", proc_path);
57  return 1;
58  } else if (rc < 0) {
59  crm_perror(LOG_ERR, "Could not read from %s", proc_path);
60  return 0;
61  }
62 
63  exe_path[rc] = 0;
64 
65  if (daemon[0] != '/') {
66  rc = snprintf(myexe_path, sizeof(proc_path), CRM_DAEMON_DIR"/%s",
67  daemon);
68  myexe_path[rc] = 0;
69  } else {
70  rc = snprintf(myexe_path, sizeof(proc_path), "%s", daemon);
71  myexe_path[rc] = 0;
72  }
73 
74  if (strcmp(exe_path, myexe_path) == 0) {
75  return 1;
76  }
77  }
78 
79  return 0;
80 }
81 
82 #define LOCKSTRLEN 11
83 
84 long
85 crm_read_pidfile(const char *filename)
86 {
87  int fd;
88  struct stat sbuf;
89  long pid = -ENOENT;
90  char buf[LOCKSTRLEN + 1];
91 
92  fd = open(filename, O_RDONLY);
93  if (fd < 0) {
94  goto bail;
95  }
96 
97  if ((fstat(fd, &sbuf) >= 0) && (sbuf.st_size < LOCKSTRLEN)) {
98  sleep(2); /* if someone was about to create one,
99  * give'm a sec to do so
100  */
101  }
102 
103  if (read(fd, buf, sizeof(buf)) < 1) {
104  goto bail;
105  }
106 
107  if (sscanf(buf, "%ld", &pid) > 0) {
108  if (pid <= 0) {
109  pid = -ESRCH;
110  } else {
111  crm_trace("Got pid %lu from %s\n", pid, filename);
112  }
113  }
114 
115  bail:
116  if (fd >= 0) {
117  close(fd);
118  }
119  return pid;
120 }
121 
122 long
123 crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
124 {
125  long pid = crm_read_pidfile(filename);
126 
127  if (pid < 2) {
128  // Invalid pid
129  pid = -ENOENT;
130  unlink(filename);
131 
132  } else if (mypid && (pid == mypid)) {
133  // In use by us
134  pid = pcmk_ok;
135 
136  } else if (crm_pid_active(pid, daemon) == FALSE) {
137  // Contains a stale value
138  unlink(filename);
139  pid = -ENOENT;
140 
141  } else if (mypid && (pid != mypid)) {
142  // Locked by existing process
143  pid = -EEXIST;
144  }
145 
146  return pid;
147 }
148 
149 int
150 crm_lock_pidfile(const char *filename, const char *name)
151 {
152  long mypid = 0;
153  int fd = 0;
154  int rc = 0;
155  char buf[LOCKSTRLEN + 2];
156 
157  mypid = (unsigned long) getpid();
158 
159  rc = crm_pidfile_inuse(filename, 0, name);
160  if (rc == -ENOENT) {
161  // Exists, but the process is not active
162 
163  } else if (rc != pcmk_ok) {
164  // Locked by existing process
165  return rc;
166  }
167 
168  fd = open(filename, O_CREAT | O_WRONLY | O_EXCL, 0644);
169  if (fd < 0) {
170  return -errno;
171  }
172 
173  snprintf(buf, sizeof(buf), "%*ld\n", LOCKSTRLEN - 1, mypid);
174  rc = write(fd, buf, LOCKSTRLEN);
175  close(fd);
176 
177  if (rc != LOCKSTRLEN) {
178  crm_perror(LOG_ERR, "Incomplete write to %s", filename);
179  return -errno;
180  }
181 
182  return crm_pidfile_inuse(filename, mypid, name);
183 }
A dumping ground.
uint32_t pid
Definition: internal.h:78
long crm_read_pidfile(const char *filename)
Definition: pid.c:85
int daemon(int nochdir, int noclose)
#define CRM_DAEMON_DIR
Definition: config.h:41
#define crm_trace(fmt, args...)
Definition: logging.h:255
long crm_pidfile_inuse(const char *filename, long mypid, const char *daemon)
Definition: pid.c:123
int crm_pid_active(long pid, const char *daemon)
Definition: pid.c:21
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:227
int crm_lock_pidfile(const char *filename, const char *name)
Definition: pid.c:150
#define pcmk_ok
Definition: results.h:35
#define LOCKSTRLEN
Definition: pid.c:82