pacemaker 2.1.5-a3f44794f94
Scalable High-Availability cluster resource manager
procfs.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-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 <stdlib.h>
18#include <string.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <dirent.h>
22#include <ctype.h>
23
39static int
40pcmk__procfs_process_info(const struct dirent *entry, char *name, pid_t *pid)
41{
42 int fd, local_pid;
43 FILE *file;
44 struct stat statbuf;
45 char procpath[128] = { 0 };
46
47 /* We're only interested in entries whose name is a PID,
48 * so skip anything non-numeric or that is too long.
49 *
50 * 114 = 128 - strlen("/proc/") - strlen("/status") - 1
51 */
52 local_pid = atoi(entry->d_name);
53 if ((local_pid <= 0) || (strlen(entry->d_name) > 114)) {
54 return -1;
55 }
56 if (pid) {
57 *pid = (pid_t) local_pid;
58 }
59
60 /* Get this entry's file information */
61 strcpy(procpath, "/proc/");
62 strcat(procpath, entry->d_name);
63 fd = open(procpath, O_RDONLY);
64 if (fd < 0 ) {
65 return -1;
66 }
67 if (fstat(fd, &statbuf) < 0) {
68 close(fd);
69 return -1;
70 }
71 close(fd);
72
73 /* We're only interested in subdirectories */
74 if (!S_ISDIR(statbuf.st_mode)) {
75 return -1;
76 }
77
78 /* Read the first entry ("Name:") from the process's status file.
79 * We could handle the valgrind case if we parsed the cmdline file
80 * instead, but that's more of a pain than it's worth.
81 */
82 if (name != NULL) {
83 strcat(procpath, "/status");
84 file = fopen(procpath, "r");
85 if (!file) {
86 return -1;
87 }
88 if (fscanf(file, "Name:\t%15[^\n]", name) != 1) {
89 fclose(file);
90 return -1;
91 }
92 name[15] = 0;
93 fclose(file);
94 }
95
96 return 0;
97}
98
110pid_t
112{
113 DIR *dp;
114 struct dirent *entry;
115 pid_t pid = 0;
116 char entry_name[64] = { 0 };
117
118 dp = opendir("/proc");
119 if (dp == NULL) {
120 crm_notice("Can not read /proc directory to track existing components");
121 return 0;
122 }
123
124 while ((entry = readdir(dp)) != NULL) {
125 if ((pcmk__procfs_process_info(entry, entry_name, &pid) == pcmk_rc_ok)
126 && pcmk__str_eq(entry_name, name, pcmk__str_casei)
127 && (pcmk__pid_active(pid, NULL) == pcmk_rc_ok)) {
128
129 crm_info("Found %s active as process %lld", name, (long long) pid);
130 break;
131 }
132 pid = 0;
133 }
134 closedir(dp);
135 return pid;
136}
137
144unsigned int
146{
147 int cores = 0;
148 FILE *stream = NULL;
149
150 /* Parse /proc/stat instead of /proc/cpuinfo because it's smaller */
151 stream = fopen("/proc/stat", "r");
152 if (stream == NULL) {
153 crm_perror(LOG_INFO, "Could not open /proc/stat");
154 } else {
155 char buffer[2048];
156
157 while (fgets(buffer, sizeof(buffer), stream)) {
158 if (pcmk__starts_with(buffer, "cpu") && isdigit(buffer[3])) {
159 ++cores;
160 }
161 }
162 fclose(stream);
163 }
164 return cores? cores : 1;
165}
166
178int
179pcmk__procfs_pid2path(pid_t pid, char path[], size_t path_size)
180{
181#if HAVE_LINUX_PROCFS
182 char procfs_exe_path[PATH_MAX];
183 ssize_t link_rc;
184
185 if (snprintf(procfs_exe_path, PATH_MAX, "/proc/%lld/exe",
186 (long long) pid) >= PATH_MAX) {
187 return ENAMETOOLONG; // Truncated (shouldn't be possible in practice)
188 }
189
190 link_rc = readlink(procfs_exe_path, path, path_size - 1);
191 if (link_rc < 0) {
192 return errno;
193 } else if (link_rc >= (path_size - 1)) {
194 return ENAMETOOLONG;
195 }
196
197 path[link_rc] = '\0';
198 return pcmk_rc_ok;
199#else
200 return EOPNOTSUPP;
201#endif // HAVE_LINUX_PROCFS
202}
203
210bool
212{
213#if HAVE_LINUX_PROCFS
214 static bool have_pids = false;
215 static bool checked = false;
216
217 if (!checked) {
218 char path[PATH_MAX];
219
220 have_pids = pcmk__procfs_pid2path(getpid(), path, sizeof(path)) == pcmk_rc_ok;
221 checked = true;
222 }
223 return have_pids;
224#else
225 return false;
226#endif // HAVE_LINUX_PROCFS
227}
const char * path
Definition: cib.c:26
const char * name
Definition: cib.c:24
int pcmk__pid_active(pid_t pid, const char *daemon)
Definition: pid.c:23
uint32_t pid
Definition: cpg.c:1
#define crm_info(fmt, args...)
Definition: logging.h:362
#define crm_notice(fmt, args...)
Definition: logging.h:361
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
Definition: logging.h:310
unsigned int pcmk__procfs_num_cores(void)
Definition: procfs.c:145
bool pcmk__procfs_has_pids(void)
Definition: procfs.c:211
pid_t pcmk__procfs_pid_of(const char *name)
Definition: procfs.c:111
int pcmk__procfs_pid2path(pid_t pid, char path[], size_t path_size)
Definition: procfs.c:179
@ pcmk_rc_ok
Definition: results.h:148
bool pcmk__starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:484
@ pcmk__str_casei