Ticket #18828: collect-ps.c

File collect-ps.c, 5.9 KB (added by LupusMichaelis, 3 months ago)

The monitoring tool to watch team ids

Line 
1#include <errno.h>
2#include <getopt.h>
3#include <stdbool.h>
4#include <stdio.h>
5#include <stdlib.h>
6
7#include <kernel/OS.h>
8
9char const watch_log[] = "/system/var/log/watch-pid.log";
10char const error_log[] = "/system/var/log/watch-pid.err";
11bigtime_t const waiting = 60 * 1000 * 1000;
12
13typedef struct
14{
15 team_id last;
16 team_id max;
17} team_stat_t;
18
19typedef struct
20{
21 char when[255];
22 team_stat_t ts;
23 bool can_spawn_process;
24 bool can_spawn_thread;
25} log_entry_t;
26
27bool print_log_entry(log_entry_t * le);
28bool watch_pid();
29void print_current_team_id();
30void collect_team_stats(team_stat_t * ts);
31bool can_spawn_process();
32bool can_spawn_thread();
33
34struct
35{
36 bool watch;
37 bool has_watch_log;
38 bool has_error_log;
39
40 char watch_log[1024];
41 char error_log[1024];
42
43 FILE * err_log_fd;
44} collect_ps;
45
46void print_collect_ps()
47{
48 printf(
49 "Watch: %s\n"
50 "has_watch_log: %s (%s)\n"
51 "has_error_log: %s (%s)\n"
52 , collect_ps.watch ? "ok" : "ko"
53 , collect_ps.has_watch_log ? "ok" : "ko"
54 , collect_ps.watch_log
55 , collect_ps.has_error_log ? "ok" : "ko"
56 , collect_ps.error_log
57 );
58}
59
60void print_error(const char * fmt, ...)
61{
62 if(collect_ps.has_error_log)
63 {
64 if(stderr == collect_ps.err_log_fd)
65 {
66 FILE * f = fopen(collect_ps.error_log, "a");
67 if(NULL == f)
68 {
69 collect_ps.has_error_log = false;
70 print_error("Cannot open '%s': %s\n", collect_ps.error_log, strerror(errno));
71 return;
72 }
73
74 collect_ps.err_log_fd = f;
75 }
76 }
77
78 va_list args;
79 va_start(args, fmt);
80 vfprintf(collect_ps.err_log_fd, fmt, args);
81 va_end(args);
82
83 fflush(collect_ps.err_log_fd);
84}
85
86bool is_option_of_name(struct option options[], int option_index, char const name[], size_t name_size)
87{
88 return 0 == strncmp(name, options[option_index].name, name_size);
89}
90
91void copy_file_option(bool * has, char * dst, size_t expected)
92{
93 if('-' == optarg[0] && '\0' == optarg[1])
94 {
95 *has = false;
96 dst[0] = '\0';
97
98 return;
99 }
100
101 size_t s = strlcpy(dst, optarg, expected);
102 if(s > expected)
103 exit(EXIT_FAILURE);
104 *has = true;
105}
106
107bool process_options(int argc, char **argv)
108{
109 collect_ps.watch = false;
110 collect_ps.err_log_fd = stderr;
111
112 size_t s = 0;
113
114 collect_ps.has_watch_log = true;
115 s = strlcpy(collect_ps.watch_log, watch_log, sizeof watch_log);
116 if(s > sizeof watch_log)
117 exit(EXIT_FAILURE);
118
119 collect_ps.has_error_log = true;
120 s = strlcpy(collect_ps.error_log, error_log, sizeof error_log);
121 if(s > sizeof error_log)
122 exit(EXIT_FAILURE);
123
124 struct {
125 int watch;
126 } so;
127
128 struct option options[] =
129 { {"watch", no_argument, &so.watch, 'w'}
130 , {"log", required_argument, 0, 'l'}
131 , {"error", required_argument, 0, 'e'}
132 , {0, 0, 0, 0}
133 };
134 int option_index = 0;
135
136 opterr = 0;
137 do
138 {
139 int c = getopt_long(argc, argv, "wl:e:", options, &option_index);
140
141 if(-1 == c)
142 break;
143
144 switch(c)
145 {
146 case 0:
147 if(is_option_of_name(options, option_index, "watch", sizeof "watch"))
148 collect_ps.watch = (bool) so.watch;
149 else if(is_option_of_name(options, option_index, "log-file", sizeof "log-file"))
150 copy_file_option(&collect_ps.has_watch_log, collect_ps.watch_log, sizeof collect_ps.watch_log);
151 else if(is_option_of_name(options, option_index, "error-file", sizeof "error-file"))
152 copy_file_option(&collect_ps.has_error_log, collect_ps.error_log, sizeof collect_ps.error_log);
153
154 break;
155
156 case 'l':
157 copy_file_option(&collect_ps.has_watch_log, collect_ps.watch_log, sizeof collect_ps.watch_log);
158 break;
159
160 case 'e':
161 copy_file_option(&collect_ps.has_error_log, collect_ps.error_log, sizeof collect_ps.error_log);
162 break;
163
164 case 'w':
165 collect_ps.watch = true;
166 break;
167
168 case '?':
169 fprintf(stderr, "Unsupported command '%c' '%s'\n", optopt, optarg ? optarg : "(null)");
170 break;
171
172 default:
173 return false;
174 }
175 } while(true);
176
177 return true;
178}
179
180int main(int argc, char * argv[])
181{
182 process_options(argc, argv);
183
184 if(collect_ps.watch)
185 return watch_pid()
186 ? EXIT_SUCCESS
187 : EXIT_FAILURE;
188
189 print_current_team_id();
190 return EXIT_SUCCESS;
191}
192
193bool can_spawn_process()
194{
195 pid_t pid = fork();
196 if(0 == pid)
197 // in child, just bail
198 exit(EXIT_SUCCESS);
199
200 if(-1 == pid)
201 {
202 print_error("Failing to spawn child: %s\n", strerror(errno));
203 return false;
204 }
205
206 return true;
207}
208
209int32 thread_dud(void * d)
210{
211 (void) d;
212 return 0;
213}
214
215bool can_spawn_thread()
216{
217 thread_id tid = spawn_thread
218 ( &thread_dud
219 , "probe thread"
220 , 0
221 , NULL
222 );
223
224 if(B_NO_MORE_THREADS == tid || B_NO_MEMORY == tid)
225 return false;
226
227 status_t ret = resume_thread(tid);
228 return B_OK == ret;
229}
230
231void print_current_team_id()
232{
233 team_info ti;
234 bzero(&ti, sizeof ti);
235 get_team_info(0, &ti);
236
237 printf("%d\n", ti.team);
238}
239
240void collect_team_stats(team_stat_t * ts)
241{
242 int32 cookie = 0;
243 team_info ti;
244
245 bzero(&ti, sizeof ti);
246 bzero(ts, sizeof *ts);
247
248 while(B_OK == get_next_team_info(&cookie, &ti))
249 {
250 ts->last = ti.team;
251 ts->max = MAX(ts->last, ts->max);
252 }
253}
254
255bool watch_pid()
256{
257 do
258 {
259 log_entry_t le;
260 collect_team_stats(&le.ts);
261
262 time_t t = time(NULL);
263 struct tm * now = localtime(&t);
264 if(NULL == now)
265 {
266 print_error("Time error: %s\n", strerror(errno));
267 return false;
268 }
269
270 size_t s = strftime(le.when, sizeof le.when - 1, "%Y-%m-%d-%H:%M:%S", now);
271 if(s > sizeof le.when - 1)
272 {
273 print_error("Error on making timestamp\n");
274 return false;
275 }
276
277 le.can_spawn_process = can_spawn_process();
278 le.can_spawn_thread = can_spawn_thread();
279
280 if(!print_log_entry(&le))
281 return false;
282
283 status_t ret = snooze(waiting);
284 if(B_INTERRUPTED == ret)
285 break;
286 }
287 while(true);
288
289 return true;
290}
291
292bool print_log_entry(log_entry_t * le)
293{
294 FILE * f = NULL;
295 if(collect_ps.has_watch_log)
296 {
297 f = fopen(collect_ps.watch_log, "a");
298 if(NULL == f)
299 {
300 print_error("Cannot open '%s': %s\n", collect_ps.watch_log, strerror(errno));
301 return false;
302 }
303 }
304 else
305 f = stdout;
306
307 fprintf
308 ( f
309 , "%s\t% 12d\t% 12d\tprocess(%s)\tthread(%s)\n"
310 , le->when
311 , le->ts.max
312 , le->ts.last
313 , le->can_spawn_process ? "ok" : "ko"
314 , le->can_spawn_thread ? "ok" : "ko"
315 );
316
317 if(collect_ps.has_watch_log)
318 fclose(f);
319
320 return true;
321}