daemon: don't skip a2j when counting ladish started clients
[ladish.git] / daemon / procfs.c
blobfdd050638324390cd33ddc4e34bb8bd18c438b67
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains the code that interfaces procfs
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <stdbool.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <errno.h>
37 #include "procfs.h"
39 #define BUFFER_SIZE 4096
41 static char g_buffer[BUFFER_SIZE];
43 static
44 bool
45 procfs_get_process_file(
46 unsigned long long pid,
47 const char * filename,
48 char ** buffer_ptr_ptr,
49 size_t * size_ptr)
51 int fd;
52 ssize_t ret;
53 size_t max;
54 char * buffer_ptr;
55 char * read_ptr;
56 size_t buffer_size;
57 size_t used_size;
59 sprintf(g_buffer, "/proc/%llu/%s", pid, filename);
61 fd = open(g_buffer, O_RDONLY);
62 if (fd == -1)
64 return false;
67 buffer_size = BUFFER_SIZE;
68 buffer_ptr = malloc(buffer_size);
69 if (buffer_ptr == NULL)
71 log_error("malloc failed to allocate buffer with size %zu", buffer_size);
72 return false;
75 used_size = 0;
76 read_ptr = buffer_ptr;
77 loop:
78 max = buffer_size - used_size;
79 if (max < BUFFER_SIZE / 4)
81 buffer_size = used_size + BUFFER_SIZE;
82 read_ptr = realloc(buffer_ptr, buffer_size);
83 if (read_ptr == NULL)
85 log_error("realloc failed to allocate buffer with size %zu", buffer_size);
86 free(buffer_ptr);
87 close(fd);
88 return false;
91 buffer_ptr = read_ptr;
92 read_ptr = buffer_ptr + used_size;
93 max = BUFFER_SIZE;
96 ret = read(fd, read_ptr, max);
97 if (ret > 0)
99 ASSERT(ret <= max);
100 read_ptr += ret;
101 used_size += ret;
102 ASSERT(used_size <= buffer_size);
103 goto loop;
106 close(fd);
108 if (ret < 0)
110 ASSERT(ret == -1);
111 close(fd);
112 return false;
115 if (used_size == buffer_size)
117 buffer_ptr = realloc(buffer_ptr, buffer_size + 1);
118 if (buffer_ptr == NULL)
120 log_error("realloc failed to allocate buffer with size %zu", buffer_size + 1);
121 return false;
125 buffer_ptr[buffer_size] = 0;
127 *buffer_ptr_ptr = buffer_ptr;
128 *size_ptr = used_size;
130 return true;
133 static
134 char *
135 procfs_get_process_link(
136 unsigned long long pid,
137 const char * filename)
139 int fd;
140 ssize_t ret;
141 char * buffer_ptr;
143 sprintf(g_buffer, "/proc/%llu/%s", pid, filename);
145 fd = open(g_buffer, O_RDONLY);
146 if (fd == -1)
148 return NULL;
151 ret = readlink(g_buffer, g_buffer, sizeof(g_buffer));
152 if (ret != 0)
154 g_buffer[ret] = 0;
155 buffer_ptr = strdup(g_buffer);
156 log_debug("process %llu %s symlink points to \"%s\"", pid, filename, buffer_ptr);
158 else
160 ASSERT(ret == -1);
161 buffer_ptr = NULL;
164 close(fd);
166 return buffer_ptr;
169 bool
170 procfs_get_process_cmdline(
171 unsigned long long pid,
172 int * argc_ptr,
173 char *** argv_ptr)
175 char * cmdline_ptr;
176 char * temp_ptr;
177 size_t cmdline_size;
178 int i;
179 int argc;
180 char ** argv;
182 if (!procfs_get_process_file(pid, "cmdline", &cmdline_ptr, &cmdline_size))
184 return false;
187 argc = 0;
188 temp_ptr = cmdline_ptr;
190 while (temp_ptr - cmdline_ptr < cmdline_size)
192 if (*temp_ptr == 0)
194 argc++;
197 temp_ptr++;
200 ASSERT(*(temp_ptr - 1) == 0); /* the last nul char */
202 argv = malloc((argc + 1) * sizeof(char *));
203 if (argv == NULL)
205 free(cmdline_ptr);
206 return false;
209 temp_ptr = cmdline_ptr;
211 for (i = 0; i < argc; i++)
213 ASSERT(temp_ptr - cmdline_ptr < cmdline_size);
215 argv[i] = strdup(temp_ptr);
216 if (argv[i] == NULL)
218 /* rollback */
219 while (i > 0)
221 i--;
222 free(argv[i]);
225 free(argv);
226 free(cmdline_ptr);
227 return false;
230 temp_ptr += strlen(temp_ptr) + 1;
233 /* Make sure that the array is NULL terminated */
234 argv[argc] = NULL;
236 *argc_ptr = argc;
237 *argv_ptr = argv;
239 free(cmdline_ptr);
241 return true;
244 char *
245 procfs_get_process_cwd(
246 unsigned long long pid)
248 return procfs_get_process_link(pid, "cwd");
251 unsigned long long
252 procfs_get_process_parent(
253 unsigned long long pid)
255 char * buffer_ptr;
256 size_t buffer_size;
257 char * begin;
258 char * end;
259 unsigned long long ppid;
261 if (!procfs_get_process_file(pid, "status", &buffer_ptr, &buffer_size))
263 return 0;
266 begin = strstr(buffer_ptr, "\nPPid:\t");
267 if (begin == NULL)
269 log_error("parent pid not parsed for %llu", pid);
270 log_error("-----------------------------");
271 log_error("%s", buffer_ptr);
272 log_error("-----------------------------");
273 return 0;
276 begin += 7;
278 end = strchr(begin, '\n');
279 if (end == NULL)
281 log_error("parent pid not parsed for %llu (end)", pid);
282 log_error("-----------------------------");
283 log_error("%s", buffer_ptr);
284 log_error("-----------------------------");
285 return 0;
288 *end = 0;
289 //log_info("parent pid is %s", begin);
291 errno = 0;
292 ppid = strtoull(begin, &end, 10);
293 if (errno != 0)
295 log_error("strtoull failed to convert '%s' to integer", begin);
296 ppid = 0;
298 else
300 //log_info("parent pid is %llu", ppid);
303 /* avoid infinite cycles (should not happen because init has pid 1 and parent 0) */
304 if (ppid == pid)
306 ppid = 0;
309 free(buffer_ptr);
311 return ppid;