pacemaker  1.1.15-e174ec8
Scalable High-Availability cluster resource manager
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
procfs.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Andrew Beekhof <andrew@beekhof.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include <crm_internal.h>
20 
21 #ifndef _GNU_SOURCE
22 # define _GNU_SOURCE
23 #endif
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <dirent.h>
31 
32 /*
33  * \internal
34  * \brief Get process ID and name associated with a /proc directory entry
35  *
36  * \param[in] entry Directory entry (must be result of readdir() on /proc)
37  * \param[out] name If not NULL, a char[64] to hold the process name
38  * \param[out] pid If not NULL, will be set to process ID of entry
39  *
40  * \return 0 on success, -1 if entry is not for a process or info not found
41  *
42  * \note This should be called only on Linux systems, as not all systems that
43  * support /proc store process names and IDs in the same way.
44  */
45 int
46 crm_procfs_process_info(struct dirent *entry, char *name, int *pid)
47 {
48  int fd, local_pid;
49  FILE *file;
50  struct stat statbuf;
51  char key[16] = { 0 }, procpath[128] = { 0 };
52 
53  /* We're only interested in entries whose name is a PID,
54  * so skip anything non-numeric or that is too long.
55  *
56  * 114 = 128 - strlen("/proc/") - strlen("/status") - 1
57  */
58  local_pid = atoi(entry->d_name);
59  if ((local_pid <= 0) || (strlen(entry->d_name) > 114)) {
60  return -1;
61  }
62  if (pid) {
63  *pid = local_pid;
64  }
65 
66  /* Get this entry's file information */
67  strcpy(procpath, "/proc/");
68  strcat(procpath, entry->d_name);
69  fd = open(procpath, O_RDONLY);
70  if (fd < 0 ) {
71  return -1;
72  }
73  if (fstat(fd, &statbuf) < 0) {
74  close(fd);
75  return -1;
76  }
77  close(fd);
78 
79  /* We're only interested in subdirectories */
80  if (!S_ISDIR(statbuf.st_mode)) {
81  return -1;
82  }
83 
84  /* Read the first entry ("Name:") from the process's status file.
85  * We could handle the valgrind case if we parsed the cmdline file
86  * instead, but that's more of a pain than it's worth.
87  */
88  if (name != NULL) {
89  strcat(procpath, "/status");
90  file = fopen(procpath, "r");
91  if (!file) {
92  return -1;
93  }
94  if ((fscanf(file, "%15s%63s", key, name) != 2)
95  || safe_str_neq(key, "Name:")) {
96  fclose(file);
97  return -1;
98  }
99  fclose(file);
100  }
101 
102  return 0;
103 }
104 
105 /*
106  * \internal
107  * \brief Return process ID of a named process
108  *
109  * \param[in] name Process name (as used in /proc/.../status)
110  *
111  * \return Process ID of named process if running, 0 otherwise
112  *
113  * \note This will return 0 if the process is being run via valgrind.
114  * This should be called only on Linux systems.
115  */
116 int
117 crm_procfs_pid_of(const char *name)
118 {
119  DIR *dp;
120  struct dirent *entry;
121  int pid = 0;
122  char entry_name[64] = { 0 };
123 
124  dp = opendir("/proc");
125  if (dp == NULL) {
126  crm_notice("Can not read /proc directory to track existing components");
127  return 0;
128  }
129 
130  while ((entry = readdir(dp)) != NULL) {
131  if ((crm_procfs_process_info(entry, entry_name, &pid) == 0)
132  && safe_str_eq(entry_name, name)
133  && (crm_pid_active(pid, NULL) == 1)) {
134 
135  crm_info("Found %s active as process %d", name, pid);
136  break;
137  }
138  pid = 0;
139  }
140  closedir(dp);
141  return pid;
142 }
#define crm_notice(fmt, args...)
Definition: logging.h:250
int crm_pid_active(long pid, const char *daemon)
Definition: utils.c:1216
gboolean safe_str_neq(const char *a, const char *b)
Definition: utils.c:696
uint32_t pid
Definition: internal.h:49
int crm_procfs_process_info(struct dirent *entry, char *name, int *pid)
Definition: procfs.c:46
#define safe_str_eq(a, b)
Definition: util.h:74
#define crm_info(fmt, args...)
Definition: logging.h:251
int crm_procfs_pid_of(const char *name)
Definition: procfs.c:117