ladishd: Basic recent projects functionality
[ladish.git] / daemon / procfs.c
blob40e7ccbde96ea8b8f1010e196d6f73f3262de47d
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009,2010 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 close(fd);
73 return false;
76 used_size = 0;
77 read_ptr = buffer_ptr;
78 loop:
79 max = buffer_size - used_size;
80 if (max < BUFFER_SIZE / 4)
82 buffer_size = used_size + BUFFER_SIZE;
83 read_ptr = realloc(buffer_ptr, buffer_size);
84 if (read_ptr == NULL)
86 log_error("realloc failed to allocate buffer with size %zu", buffer_size);
87 free(buffer_ptr);
88 close(fd);
89 return false;
92 buffer_ptr = read_ptr;
93 read_ptr = buffer_ptr + used_size;
94 max = BUFFER_SIZE;
97 ret = read(fd, read_ptr, max);
98 if (ret > 0)
100 ASSERT(ret <= max);
101 read_ptr += ret;
102 used_size += ret;
103 ASSERT(used_size <= buffer_size);
104 goto loop;
107 close(fd);
109 if (ret < 0)
111 ASSERT(ret == -1);
112 return false;
115 if (used_size == buffer_size)
117 read_ptr = realloc(buffer_ptr, buffer_size + 1);
118 if (read_ptr == NULL)
120 log_error("realloc failed to allocate buffer with size %zu", buffer_size + 1);
121 free(buffer_ptr);
122 return false;
125 buffer_ptr = read_ptr;
128 buffer_ptr[used_size] = 0;
130 *buffer_ptr_ptr = buffer_ptr;
131 *size_ptr = used_size;
133 return true;
136 static
137 char *
138 procfs_get_process_link(
139 unsigned long long pid,
140 const char * filename)
142 int fd;
143 ssize_t ret;
144 char * buffer_ptr;
146 sprintf(g_buffer, "/proc/%llu/%s", pid, filename);
148 fd = open(g_buffer, O_RDONLY);
149 if (fd == -1)
151 return NULL;
154 ret = readlink(g_buffer, g_buffer, sizeof(g_buffer));
155 if (ret != 0)
157 g_buffer[ret] = 0;
158 buffer_ptr = strdup(g_buffer);
159 log_debug("process %llu %s symlink points to \"%s\"", pid, filename, buffer_ptr);
161 else
163 ASSERT(ret == -1);
164 buffer_ptr = NULL;
167 close(fd);
169 return buffer_ptr;
172 bool
173 procfs_get_process_cmdline(
174 unsigned long long pid,
175 int * argc_ptr,
176 char *** argv_ptr)
178 char * cmdline_ptr;
179 char * temp_ptr;
180 size_t cmdline_size;
181 int i;
182 int argc;
183 char ** argv;
185 if (!procfs_get_process_file(pid, "cmdline", &cmdline_ptr, &cmdline_size))
187 return false;
190 argc = 0;
191 temp_ptr = cmdline_ptr;
193 while (temp_ptr - cmdline_ptr < cmdline_size)
195 if (*temp_ptr == 0)
197 argc++;
200 temp_ptr++;
203 ASSERT(*(temp_ptr - 1) == 0); /* the last nul char */
205 argv = malloc((argc + 1) * sizeof(char *));
206 if (argv == NULL)
208 free(cmdline_ptr);
209 return false;
212 temp_ptr = cmdline_ptr;
214 for (i = 0; i < argc; i++)
216 ASSERT(temp_ptr - cmdline_ptr < cmdline_size);
218 argv[i] = strdup(temp_ptr);
219 if (argv[i] == NULL)
221 /* rollback */
222 while (i > 0)
224 i--;
225 free(argv[i]);
228 free(argv);
229 free(cmdline_ptr);
230 return false;
233 temp_ptr += strlen(temp_ptr) + 1;
236 /* Make sure that the array is NULL terminated */
237 argv[argc] = NULL;
239 *argc_ptr = argc;
240 *argv_ptr = argv;
242 free(cmdline_ptr);
244 return true;
247 char *
248 procfs_get_process_cwd(
249 unsigned long long pid)
251 return procfs_get_process_link(pid, "cwd");
254 unsigned long long
255 procfs_get_process_parent(
256 unsigned long long pid)
258 char * buffer_ptr;
259 size_t buffer_size;
260 char * begin;
261 char * end;
262 unsigned long long ppid;
264 if (!procfs_get_process_file(pid, "status", &buffer_ptr, &buffer_size))
266 return 0;
269 begin = strstr(buffer_ptr, "\nPPid:\t");
270 if (begin == NULL)
272 log_error("parent pid not parsed for %llu", pid);
273 log_error("-----------------------------");
274 log_error("%s", buffer_ptr);
275 log_error("-----------------------------");
276 free(buffer_ptr);
277 return 0;
280 begin += 7;
282 end = strchr(begin, '\n');
283 if (end == NULL)
285 log_error("parent pid not parsed for %llu (end)", pid);
286 log_error("-----------------------------");
287 log_error("%s", buffer_ptr);
288 log_error("-----------------------------");
289 free(buffer_ptr);
290 return 0;
293 *end = 0;
294 //log_info("parent pid is %s", begin);
296 errno = 0;
297 ppid = strtoull(begin, &end, 10);
298 if (errno != 0)
300 log_error("strtoull failed to convert '%s' to integer", begin);
301 ppid = 0;
303 else
305 //log_info("parent pid is %llu", ppid);
308 /* avoid infinite cycles (should not happen because init has pid 1 and parent 0) */
309 if (ppid == pid)
311 ppid = 0;
314 free(buffer_ptr);
316 return ppid;