pacemaker  2.0.2-debe490
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
procfs.c
Go to the documentation of this file.
1 /*
2  * Copyright 2015-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 <stdlib.h>
16 #include <string.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <dirent.h>
20 #include <ctype.h>
21 
38 int
39 crm_procfs_process_info(struct dirent *entry, char *name, int *pid)
40 {
41  int fd, local_pid;
42  FILE *file;
43  struct stat statbuf;
44  char procpath[128] = { 0 };
45 
46  /* We're only interested in entries whose name is a PID,
47  * so skip anything non-numeric or that is too long.
48  *
49  * 114 = 128 - strlen("/proc/") - strlen("/status") - 1
50  */
51  local_pid = atoi(entry->d_name);
52  if ((local_pid <= 0) || (strlen(entry->d_name) > 114)) {
53  return -1;
54  }
55  if (pid) {
56  *pid = local_pid;
57  }
58 
59  /* Get this entry's file information */
60  strcpy(procpath, "/proc/");
61  strcat(procpath, entry->d_name);
62  fd = open(procpath, O_RDONLY);
63  if (fd < 0 ) {
64  return -1;
65  }
66  if (fstat(fd, &statbuf) < 0) {
67  close(fd);
68  return -1;
69  }
70  close(fd);
71 
72  /* We're only interested in subdirectories */
73  if (!S_ISDIR(statbuf.st_mode)) {
74  return -1;
75  }
76 
77  /* Read the first entry ("Name:") from the process's status file.
78  * We could handle the valgrind case if we parsed the cmdline file
79  * instead, but that's more of a pain than it's worth.
80  */
81  if (name != NULL) {
82  strcat(procpath, "/status");
83  file = fopen(procpath, "r");
84  if (!file) {
85  return -1;
86  }
87  if (fscanf(file, "Name:\t%15[^\n]", name) != 1) {
88  fclose(file);
89  return -1;
90  }
91  name[15] = 0;
92  fclose(file);
93  }
94 
95  return 0;
96 }
97 
109 int
110 crm_procfs_pid_of(const char *name)
111 {
112  DIR *dp;
113  struct dirent *entry;
114  int pid = 0;
115  char entry_name[64] = { 0 };
116 
117  dp = opendir("/proc");
118  if (dp == NULL) {
119  crm_notice("Can not read /proc directory to track existing components");
120  return 0;
121  }
122 
123  while ((entry = readdir(dp)) != NULL) {
124  if ((crm_procfs_process_info(entry, entry_name, &pid) == 0)
125  && safe_str_eq(entry_name, name)
126  && (crm_pid_active(pid, NULL) == 1)) {
127 
128  crm_info("Found %s active as process %d", name, pid);
129  break;
130  }
131  pid = 0;
132  }
133  closedir(dp);
134  return pid;
135 }
136 
143 unsigned int
145 {
146  int cores = 0;
147  FILE *stream = NULL;
148 
149  /* Parse /proc/stat instead of /proc/cpuinfo because it's smaller */
150  stream = fopen("/proc/stat", "r");
151  if (stream == NULL) {
152  crm_perror(LOG_INFO, "Could not open /proc/stat");
153  } else {
154  char buffer[2048];
155 
156  while (fgets(buffer, sizeof(buffer), stream)) {
157  if (crm_starts_with(buffer, "cpu") && isdigit(buffer[3])) {
158  ++cores;
159  }
160  }
161  fclose(stream);
162  }
163  return cores? cores : 1;
164 }
#define crm_notice(fmt, args...)
Definition: logging.h:242
uint32_t pid
Definition: internal.h:83
bool crm_starts_with(const char *str, const char *prefix)
Check whether a string starts with a certain sequence.
Definition: strings.c:259
int crm_procfs_process_info(struct dirent *entry, char *name, int *pid)
Definition: procfs.c:39
int crm_pid_active(long pid, const char *daemon)
Definition: pid.c:23
unsigned int crm_procfs_num_cores(void)
Definition: procfs.c:144
#define crm_perror(level, fmt, args...)
Log a system error message.
Definition: logging.h:218
#define safe_str_eq(a, b)
Definition: util.h:59
int crm_procfs_pid_of(const char *name)
Definition: procfs.c:110
#define crm_info(fmt, args...)
Definition: logging.h:243