Add app list version number to the AppStateChanged signal and check it
[ladish.git] / daemon / procfs.c
blob846b9188b0f38abd453b92e05099ebefd54d1447
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 free(buffer_ptr);
122 return false;
126 buffer_ptr[buffer_size] = 0;
128 *buffer_ptr_ptr = buffer_ptr;
129 *size_ptr = used_size;
131 return true;
134 static
135 char *
136 procfs_get_process_link(
137 unsigned long long pid,
138 const char * filename)
140 int fd;
141 ssize_t ret;
142 char * buffer_ptr;
144 sprintf(g_buffer, "/proc/%llu/%s", pid, filename);
146 fd = open(g_buffer, O_RDONLY);
147 if (fd == -1)
149 return NULL;
152 ret = readlink(g_buffer, g_buffer, sizeof(g_buffer));
153 if (ret != 0)
155 g_buffer[ret] = 0;
156 buffer_ptr = strdup(g_buffer);
157 log_debug("process %llu %s symlink points to \"%s\"", pid, filename, buffer_ptr);
159 else
161 ASSERT(ret == -1);
162 buffer_ptr = NULL;
165 close(fd);
167 return buffer_ptr;
170 bool
171 procfs_get_process_cmdline(
172 unsigned long long pid,
173 int * argc_ptr,
174 char *** argv_ptr)
176 char * cmdline_ptr;
177 char * temp_ptr;
178 size_t cmdline_size;
179 int i;
180 int argc;
181 char ** argv;
183 if (!procfs_get_process_file(pid, "cmdline", &cmdline_ptr, &cmdline_size))
185 return false;
188 argc = 0;
189 temp_ptr = cmdline_ptr;
191 while (temp_ptr - cmdline_ptr < cmdline_size)
193 if (*temp_ptr == 0)
195 argc++;
198 temp_ptr++;
201 ASSERT(*(temp_ptr - 1) == 0); /* the last nul char */
203 argv = malloc((argc + 1) * sizeof(char *));
204 if (argv == NULL)
206 free(cmdline_ptr);
207 return false;
210 temp_ptr = cmdline_ptr;
212 for (i = 0; i < argc; i++)
214 ASSERT(temp_ptr - cmdline_ptr < cmdline_size);
216 argv[i] = strdup(temp_ptr);
217 if (argv[i] == NULL)
219 /* rollback */
220 while (i > 0)
222 i--;
223 free(argv[i]);
226 free(argv);
227 free(cmdline_ptr);
228 return false;
231 temp_ptr += strlen(temp_ptr) + 1;
234 /* Make sure that the array is NULL terminated */
235 argv[argc] = NULL;
237 *argc_ptr = argc;
238 *argv_ptr = argv;
240 free(cmdline_ptr);
242 return true;
245 char *
246 procfs_get_process_cwd(
247 unsigned long long pid)
249 return procfs_get_process_link(pid, "cwd");
252 unsigned long long
253 procfs_get_process_parent(
254 unsigned long long pid)
256 char * buffer_ptr;
257 size_t buffer_size;
258 char * begin;
259 char * end;
260 unsigned long long ppid;
262 if (!procfs_get_process_file(pid, "status", &buffer_ptr, &buffer_size))
264 return 0;
267 begin = strstr(buffer_ptr, "\nPPid:\t");
268 if (begin == NULL)
270 log_error("parent pid not parsed for %llu", pid);
271 log_error("-----------------------------");
272 log_error("%s", buffer_ptr);
273 log_error("-----------------------------");
274 free(buffer_ptr);
275 return 0;
278 begin += 7;
280 end = strchr(begin, '\n');
281 if (end == NULL)
283 log_error("parent pid not parsed for %llu (end)", pid);
284 log_error("-----------------------------");
285 log_error("%s", buffer_ptr);
286 log_error("-----------------------------");
287 free(buffer_ptr);
288 return 0;
291 *end = 0;
292 //log_info("parent pid is %s", begin);
294 errno = 0;
295 ppid = strtoull(begin, &end, 10);
296 if (errno != 0)
298 log_error("strtoull failed to convert '%s' to integer", begin);
299 ppid = 0;
301 else
303 //log_info("parent pid is %llu", ppid);
306 /* avoid infinite cycles (should not happen because init has pid 1 and parent 0) */
307 if (ppid == pid)
309 ppid = 0;
312 free(buffer_ptr);
314 return ppid;