1 |
/* |
2 |
* ccs-queryd.c |
3 |
* |
4 |
* TOMOYO Linux's utilities. |
5 |
* |
6 |
* Copyright (C) 2005-2010 NTT DATA CORPORATION |
7 |
* |
8 |
* Version: 1.8.0-pre 2010/08/01 |
9 |
* |
10 |
*/ |
11 |
#include "ccstools.h" |
12 |
#include "readline.h" |
13 |
|
14 |
#define CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE 0 |
15 |
#define CCS_GLOBALLY_READABLE_FILES_UPDATE_ASK 1 |
16 |
#define CCS_GLOBALLY_READABLE_FILES_UPDATE_AUTO 2 |
17 |
|
18 |
/* Prototypes */ |
19 |
|
20 |
static void ccs_printw(const char *fmt, ...) __attribute__ ((format(printf, 1, 2))); |
21 |
static int ccs_send_encoded(const int fd, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); |
22 |
static void ccs_do_check_update(const int fd); |
23 |
static void ccs_handle_update(const int ccs_check_update, const int fd); |
24 |
/* |
25 |
static _Bool ccs_convert_path_info(FILE *fp, const struct ccs_path_info *pattern, const char *new); |
26 |
*/ |
27 |
static _Bool ccs_handle_query(unsigned int serial); |
28 |
|
29 |
/* Utility functions */ |
30 |
|
31 |
static void ccs_printw(const char *fmt, ...) |
32 |
{ |
33 |
va_list args; |
34 |
int i; |
35 |
int len; |
36 |
char *buffer; |
37 |
va_start(args, fmt); |
38 |
len = vsnprintf((char *) &i, sizeof(i) - 1, fmt, args) + 16; |
39 |
va_end(args); |
40 |
buffer = malloc(len); |
41 |
if (!buffer) |
42 |
ccs_out_of_memory(); |
43 |
va_start(args, fmt); |
44 |
len = vsnprintf(buffer, len, fmt, args); |
45 |
va_end(args); |
46 |
for (i = 0; i < len; i++) { |
47 |
addch(buffer[i]); |
48 |
refresh(); |
49 |
} |
50 |
free(buffer); |
51 |
} |
52 |
|
53 |
static int ccs_send_encoded(const int fd, const char *fmt, ...) |
54 |
{ |
55 |
va_list args; |
56 |
int i; |
57 |
int len; |
58 |
char *buffer; |
59 |
char *sp; |
60 |
char *dp; |
61 |
va_start(args, fmt); |
62 |
len = vsnprintf((char *) &i, sizeof(i) - 1, fmt, args) + 16; |
63 |
va_end(args); |
64 |
buffer = malloc(len * 5); |
65 |
if (!buffer) |
66 |
ccs_out_of_memory(); |
67 |
va_start(args, fmt); |
68 |
vsnprintf(buffer, len, fmt, args); |
69 |
va_end(args); |
70 |
sp = buffer; |
71 |
dp = buffer + len; |
72 |
while (true) { |
73 |
unsigned char c = *(const unsigned char *) sp++; |
74 |
if (!c) { |
75 |
*dp++ = '\0'; |
76 |
break; |
77 |
} else if (c == '\\') { |
78 |
*dp++ = '\\'; |
79 |
*dp++ = '\\'; |
80 |
} else if (c > ' ' && c < 127) { |
81 |
*dp++ = c; |
82 |
} else { |
83 |
*dp++ = '\\'; |
84 |
*dp++ = (c >> 6) + '0'; |
85 |
*dp++ = ((c >> 3) & 7) + '0'; |
86 |
*dp++ = (c & 7) + '0'; |
87 |
} |
88 |
} |
89 |
len = send(fd, buffer + len, strlen(buffer + len), 0); |
90 |
free(buffer); |
91 |
return len; |
92 |
} |
93 |
|
94 |
#if 0 |
95 |
static _Bool ccs_check_path_info(const char *buffer) |
96 |
{ |
97 |
_Bool modified = false; |
98 |
static struct ccs_path_info *update_list = NULL; |
99 |
static int update_list_len = 0; |
100 |
char *sp = strdup(buffer); |
101 |
char *str = sp; |
102 |
const char *path_list[2] = { |
103 |
CCS_PROC_POLICY_EXCEPTION_POLICY, |
104 |
CCS_PROC_POLICY_DOMAIN_POLICY |
105 |
}; |
106 |
if (!str) |
107 |
return false; |
108 |
while (true) { |
109 |
int i; |
110 |
char *cp = strsep(&sp, " "); |
111 |
if (!cp) |
112 |
break; |
113 |
for (i = 0; i < update_list_len; i++) { |
114 |
int j; |
115 |
struct ccs_path_info old; |
116 |
/* TODO: split cp at upadte_list's depth. */ |
117 |
old.name = cp; |
118 |
ccs_fill_path_info(&old); |
119 |
if (!ccs_path_matches_pattern(&old, &update_list[i])) |
120 |
continue; |
121 |
for (j = 0; j < 2; j++) { |
122 |
FILE *fp = fopen(path_list[j], "r+"); |
123 |
if (!fp) |
124 |
continue; |
125 |
if (convert_path_info(fp, &update_list[i], cp)) |
126 |
modified = true; |
127 |
fclose(fp); |
128 |
} |
129 |
} |
130 |
} |
131 |
free(str); |
132 |
return modified; |
133 |
} |
134 |
#endif |
135 |
|
136 |
static void ccs_do_check_update(const int fd) |
137 |
{ |
138 |
FILE *fp_in = fopen(CCS_PROC_POLICY_EXCEPTION_POLICY, "r"); |
139 |
char **pathnames = NULL; |
140 |
int pathnames_len = 0; |
141 |
char buffer[16384]; |
142 |
memset(buffer, 0, sizeof(buffer)); |
143 |
if (!fp_in) { |
144 |
fprintf(stderr, "Can't open policy file.\n"); |
145 |
return; |
146 |
} |
147 |
while (fgets(buffer, sizeof(buffer) - 1, fp_in)) { |
148 |
char *cp = strchr(buffer, '\n'); |
149 |
if (!cp) |
150 |
break; |
151 |
*cp = '\0'; |
152 |
if (!ccs_str_starts(buffer, "acl_group ")) |
153 |
continue; |
154 |
cp = strchr(buffer, ' '); |
155 |
if (!cp) |
156 |
continue; |
157 |
memmove(buffer, cp + 1, strlen(cp + 1) + 1); |
158 |
if (!ccs_str_starts(buffer, "file read ")) |
159 |
continue; |
160 |
if (!ccs_decode(buffer, buffer)) |
161 |
continue; |
162 |
pathnames = realloc(pathnames, sizeof(char *) * |
163 |
(pathnames_len + 1)); |
164 |
if (!pathnames) |
165 |
ccs_out_of_memory(); |
166 |
pathnames[pathnames_len] = strdup(buffer); |
167 |
if (!pathnames[pathnames_len]) |
168 |
ccs_out_of_memory(); |
169 |
pathnames_len++; |
170 |
} |
171 |
fclose(fp_in); |
172 |
while (true) { |
173 |
struct stat64 buf; |
174 |
static time_t last_modified = 0; |
175 |
int i; |
176 |
sleep(1); |
177 |
for (i = 0; i < pathnames_len; i++) { |
178 |
int j; |
179 |
if (!stat64(pathnames[i], &buf)) |
180 |
continue; |
181 |
ccs_send_encoded(fd, "-%s", pathnames[i]); |
182 |
free(pathnames[i]); |
183 |
pathnames_len--; |
184 |
for (j = i; j < pathnames_len; j++) |
185 |
pathnames[j] = pathnames[j + 1]; |
186 |
i--; |
187 |
} |
188 |
if (stat64("/etc/ld.so.cache", &buf) || |
189 |
buf.st_mtime == last_modified) |
190 |
continue; |
191 |
fp_in = popen("/sbin/ldconfig -NXp", "r"); |
192 |
if (!fp_in) |
193 |
continue; |
194 |
last_modified = buf.st_mtime; |
195 |
memset(buffer, 0, sizeof(buffer)); |
196 |
while (fgets(buffer, sizeof(buffer) - 1, fp_in)) { |
197 |
char *cp = strchr(buffer, '\n'); |
198 |
char *real_pathname; |
199 |
if (!cp) |
200 |
break; |
201 |
*cp = '\0'; |
202 |
cp = strrchr(buffer, ' '); |
203 |
if (!cp || *++cp != '/') |
204 |
continue; |
205 |
if (stat64(cp, &buf)) |
206 |
continue; |
207 |
real_pathname = realpath(cp, NULL); |
208 |
if (!real_pathname) |
209 |
continue; |
210 |
for (i = 0; i < pathnames_len; i++) { |
211 |
if (!strcmp(real_pathname, pathnames[i])) |
212 |
break; |
213 |
} |
214 |
if (i == pathnames_len) { |
215 |
char *cp; |
216 |
pathnames = realloc(pathnames, sizeof(char *) * |
217 |
(pathnames_len + 1)); |
218 |
if (!pathnames) |
219 |
ccs_out_of_memory(); |
220 |
cp = strdup(real_pathname); |
221 |
if (!cp) |
222 |
ccs_out_of_memory(); |
223 |
pathnames[pathnames_len++] = cp; |
224 |
ccs_send_encoded(fd, "+%s", pathnames[i]); |
225 |
} |
226 |
free(real_pathname); |
227 |
} |
228 |
pclose(fp_in); |
229 |
} |
230 |
} |
231 |
|
232 |
#if 0 |
233 |
static _Bool ccs_convert_path_info(FILE *fp, const struct ccs_path_info *pattern, |
234 |
const char *new) |
235 |
{ |
236 |
_Bool modified = false; |
237 |
const char *cp = pattern->name; |
238 |
int depth = 0; |
239 |
while (*cp) |
240 |
if (*cp++ == '/') |
241 |
depth++; |
242 |
while (true) { |
243 |
int d = depth; |
244 |
char buffer[4096]; |
245 |
char *cp; |
246 |
if (fscanf(fp, "%4095s", buffer) != 1) |
247 |
break; |
248 |
if (buffer[0] != '/') |
249 |
goto out; |
250 |
cp = buffer; |
251 |
while (*cp) { |
252 |
char c; |
253 |
struct ccs_path_info old; |
254 |
_Bool matched; |
255 |
if (*cp != '/' || --d) |
256 |
continue; |
257 |
cp++; |
258 |
c = *cp; |
259 |
*cp = '\0'; |
260 |
old.name = buffer; |
261 |
ccs_fill_path_info(&old); |
262 |
matched = ccs_path_matches_pattern(&old, pattern); |
263 |
*cp = c; |
264 |
if (matched) { |
265 |
fprintf(fp, "%s%s", new, cp); |
266 |
modified = true; |
267 |
buffer[0] = '\0'; |
268 |
break; |
269 |
} |
270 |
} |
271 |
out: |
272 |
fprintf(fp, "%s ", buffer); |
273 |
} |
274 |
return modified; |
275 |
} |
276 |
#endif |
277 |
|
278 |
static void ccs_send_keepalive(void) |
279 |
{ |
280 |
static time_t previous = 0; |
281 |
time_t now = time(NULL); |
282 |
if (previous != now || !previous) { |
283 |
previous = now; |
284 |
write(ccs_query_fd, "\n", 1); |
285 |
} |
286 |
} |
287 |
|
288 |
static void ccs_handle_update(const int check_update, const int fd) |
289 |
{ |
290 |
static FILE *fp = NULL; |
291 |
char pathname[8192]; |
292 |
int c; |
293 |
if (!fp) |
294 |
fp = fopen(CCS_PROC_POLICY_EXCEPTION_POLICY, "w"); |
295 |
memset(pathname, 0, sizeof(pathname)); |
296 |
if (recv(fd, pathname, sizeof(pathname) - 1, 0) == EOF) |
297 |
return; |
298 |
if (check_update == CCS_GLOBALLY_READABLE_FILES_UPDATE_AUTO) { |
299 |
if (pathname[0] == '-') |
300 |
fprintf(fp, CCS_KEYWORD_DELETE); |
301 |
fprintf(fp, "acl_group 0 file read %s\n", pathname + 1); |
302 |
fflush(fp); |
303 |
ccs_printw("The pathname %s was %s globally readable file.\n\n", |
304 |
pathname + 1, (pathname[0] == '-') ? |
305 |
"deleted. Deleted from" : "created. Appended to"); |
306 |
return; |
307 |
} |
308 |
ccs_printw("The pathname %s was %s globally readable file? ('Y'es/'N'o):", |
309 |
pathname + 1, (pathname[0] == '-') ? |
310 |
"deleted. Delete from" : "created. Append to"); |
311 |
while (true) { |
312 |
c = ccs_getch2(); |
313 |
if (c == 'Y' || c == 'y' || c == 'N' || c == 'n') |
314 |
break; |
315 |
ccs_send_keepalive(); |
316 |
} |
317 |
ccs_printw("%c\n", c); |
318 |
if (c == 'Y' || c == 'y') { |
319 |
if (pathname[0] == '-') |
320 |
fprintf(fp, CCS_KEYWORD_DELETE); |
321 |
fprintf(fp, "acl_group 0 file read %s\n", pathname + 1); |
322 |
fflush(fp); |
323 |
} |
324 |
ccs_printw("\n"); |
325 |
} |
326 |
|
327 |
/* Variables */ |
328 |
|
329 |
static unsigned short int ccs_retries = 0; |
330 |
|
331 |
static int ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_AUTO; |
332 |
|
333 |
static FILE *ccs_domain_fp = NULL; |
334 |
static int ccs_domain_policy_fd = EOF; |
335 |
#define CCS_MAX_READLINE_HISTORY 20 |
336 |
static const char **ccs_readline_history = NULL; |
337 |
static int ccs_readline_history_count = 0; |
338 |
static const int ccs_buffer_len = 32768; |
339 |
static char *ccs_buffer = NULL; |
340 |
|
341 |
/* Main functions */ |
342 |
|
343 |
static _Bool ccs_handle_query(unsigned int serial) |
344 |
{ |
345 |
int c = 0; |
346 |
int y; |
347 |
int x; |
348 |
char *line = NULL; |
349 |
static unsigned int prev_pid = 0; |
350 |
unsigned int pid; |
351 |
time_t stamp; |
352 |
char pidbuf[128]; |
353 |
char *cp = strstr(ccs_buffer, " (global-pid="); |
354 |
if (!cp || sscanf(cp + 13, "%u", &pid) != 1) { |
355 |
ccs_printw("ERROR: Unsupported query.\n"); |
356 |
return false; |
357 |
} |
358 |
cp = ccs_buffer + strlen(ccs_buffer); |
359 |
if (*(cp - 1) != '\n') { |
360 |
ccs_printw("ERROR: Unsupported query.\n"); |
361 |
return false; |
362 |
} |
363 |
*(cp - 1) = '\0'; |
364 |
/* |
365 |
if (0 && !ccs_retries && check_path_info(ccs_buffer)) { |
366 |
c = 'r'; |
367 |
goto write_answer; |
368 |
} |
369 |
*/ |
370 |
if (pid != prev_pid) { |
371 |
if (prev_pid) |
372 |
ccs_printw("----------------------------------------\n"); |
373 |
prev_pid = pid; |
374 |
} |
375 |
if (sscanf(ccs_buffer, "#timestamp=%lu", &stamp) == 1) { |
376 |
cp = strchr(ccs_buffer, ' '); |
377 |
if (cp) { |
378 |
struct tm *tm = localtime(&stamp); |
379 |
ccs_printw("#%04d-%02d-%02d %02d:%02d:%02d#", |
380 |
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, |
381 |
tm->tm_hour, tm->tm_min, tm->tm_sec); |
382 |
memmove(ccs_buffer, cp, strlen(cp) + 1); |
383 |
} |
384 |
} |
385 |
ccs_printw("%s\n", ccs_buffer); |
386 |
/* Is this domain query? */ |
387 |
if (strstr(ccs_buffer, "\n#")) |
388 |
goto not_domain_query; |
389 |
memset(pidbuf, 0, sizeof(pidbuf)); |
390 |
snprintf(pidbuf, sizeof(pidbuf) - 1, "select global-pid=%u\n", pid); |
391 |
ccs_printw("Allow? ('Y'es/'N'o/'R'etry/'S'how policy/'A'dd to policy " |
392 |
"and retry):"); |
393 |
while (true) { |
394 |
c = ccs_getch2(); |
395 |
if (c == 'Y' || c == 'y' || c == 'N' || c == 'n' || c == 'R' || |
396 |
c == 'r' || c == 'A' || c == 'a' || c == 'S' || c == 's') |
397 |
break; |
398 |
ccs_send_keepalive(); |
399 |
} |
400 |
ccs_printw("%c\n", c); |
401 |
|
402 |
if (c == 'S' || c == 's') { |
403 |
if (ccs_network_mode) { |
404 |
fprintf(ccs_domain_fp, "%s", pidbuf); |
405 |
fputc(0, ccs_domain_fp); |
406 |
fflush(ccs_domain_fp); |
407 |
rewind(ccs_domain_fp); |
408 |
while (1) { |
409 |
char c; |
410 |
if (fread(&c, 1, 1, ccs_domain_fp) != 1 || !c) |
411 |
break; |
412 |
addch(c); |
413 |
refresh(); |
414 |
ccs_send_keepalive(); |
415 |
} |
416 |
} else { |
417 |
write(ccs_domain_policy_fd, pidbuf, strlen(pidbuf)); |
418 |
while (1) { |
419 |
int i; |
420 |
int len = read(ccs_domain_policy_fd, ccs_buffer, |
421 |
ccs_buffer_len - 1); |
422 |
if (len <= 0) |
423 |
break; |
424 |
for (i = 0; i < len; i++) { |
425 |
addch(ccs_buffer[i]); |
426 |
refresh(); |
427 |
} |
428 |
ccs_send_keepalive(); |
429 |
} |
430 |
} |
431 |
c = 'r'; |
432 |
} |
433 |
|
434 |
/* Append to domain policy. */ |
435 |
if (c != 'A' && c != 'a') |
436 |
goto not_append; |
437 |
c = 'r'; |
438 |
getyx(stdscr, y, x); |
439 |
cp = strrchr(ccs_buffer, '\n'); |
440 |
if (!cp) |
441 |
return false; |
442 |
*cp++ = '\0'; |
443 |
ccs_initial_readline_data = cp; |
444 |
ccs_readline_history_count = ccs_add_history(cp, ccs_readline_history, |
445 |
ccs_readline_history_count, |
446 |
CCS_MAX_READLINE_HISTORY); |
447 |
line = ccs_readline(y, 0, "Enter new entry> ", ccs_readline_history, |
448 |
ccs_readline_history_count, 128000, 8); |
449 |
scrollok(stdscr, TRUE); |
450 |
ccs_printw("\n"); |
451 |
if (!line || !*line) { |
452 |
ccs_printw("None added.\n"); |
453 |
goto not_append; |
454 |
} |
455 |
ccs_readline_history_count = ccs_add_history(line, ccs_readline_history, |
456 |
ccs_readline_history_count, |
457 |
CCS_MAX_READLINE_HISTORY); |
458 |
if (ccs_network_mode) { |
459 |
fprintf(ccs_domain_fp, "%s%s\n", pidbuf, line); |
460 |
fflush(ccs_domain_fp); |
461 |
} else { |
462 |
write(ccs_domain_policy_fd, pidbuf, strlen(pidbuf)); |
463 |
write(ccs_domain_policy_fd, line, strlen(line)); |
464 |
write(ccs_domain_policy_fd, "\n", 1); |
465 |
} |
466 |
ccs_printw("Added '%s'.\n", line); |
467 |
not_append: |
468 |
free(line); |
469 |
write_answer: |
470 |
/* Write answer. */ |
471 |
if (c == 'Y' || c == 'y' || c == 'A' || c == 'a') |
472 |
c = 1; |
473 |
else if (c == 'R' || c == 'r') |
474 |
c = 3; |
475 |
else |
476 |
c = 2; |
477 |
snprintf(ccs_buffer, ccs_buffer_len - 1, "A%u=%u\n", serial, c); |
478 |
write(ccs_query_fd, ccs_buffer, strlen(ccs_buffer)); |
479 |
ccs_printw("\n"); |
480 |
return true; |
481 |
not_domain_query: |
482 |
ccs_printw("Allow? ('Y'es/'N'o/'R'etry):"); |
483 |
while (true) { |
484 |
c = ccs_getch2(); |
485 |
if (c == 'Y' || c == 'y' || c == 'N' || c == 'n' || |
486 |
c == 'R' || c == 'r') |
487 |
break; |
488 |
ccs_send_keepalive(); |
489 |
} |
490 |
ccs_printw("%c\n", c); |
491 |
goto write_answer; |
492 |
} |
493 |
|
494 |
int main(int argc, char *argv[]) |
495 |
{ |
496 |
int pipe_fd[2] = { EOF, EOF }; |
497 |
if (argc == 1) |
498 |
goto ok; |
499 |
{ |
500 |
char *cp = strchr(argv[1], ':'); |
501 |
if (cp) { |
502 |
*cp++ = '\0'; |
503 |
ccs_network_ip = inet_addr(argv[1]); |
504 |
ccs_network_port = htons(atoi(cp)); |
505 |
ccs_network_mode = true; |
506 |
if (!ccs_check_remote_host()) |
507 |
return 1; |
508 |
ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE; |
509 |
goto ok; |
510 |
} |
511 |
} |
512 |
if (!strcmp(argv[1], "--no-update")) { |
513 |
ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE; |
514 |
goto ok; |
515 |
} |
516 |
if (!strcmp(argv[1], "--ask-update")) { |
517 |
ccs_check_update = CCS_GLOBALLY_READABLE_FILES_UPDATE_ASK; |
518 |
goto ok; |
519 |
} |
520 |
printf("Usage: %s [--no-update|--ask-update|remote_ip:remote_port]\n\n", |
521 |
argv[0]); |
522 |
printf("This program is used for granting access requests manually.\n"); |
523 |
printf("This program shows access requests that are about to rejected " |
524 |
"by the kernel's decision.\n"); |
525 |
printf("If you answer before the kernel's decision taken effect, your " |
526 |
"decision will take effect.\n"); |
527 |
printf("You can use this program to respond to accidental access " |
528 |
"requests triggered by non-routine tasks (such as restarting " |
529 |
"daemons after updating).\n"); |
530 |
printf("To terminate this program, use 'Ctrl-C'.\n"); |
531 |
return 0; |
532 |
ok: |
533 |
if (ccs_network_mode) { |
534 |
ccs_query_fd = ccs_open_stream("proc:query"); |
535 |
ccs_domain_fp = ccs_open_write(CCS_PROC_POLICY_DOMAIN_POLICY); |
536 |
} else { |
537 |
ccs_query_fd = open(CCS_PROC_POLICY_QUERY, O_RDWR); |
538 |
ccs_domain_policy_fd = open(CCS_PROC_POLICY_DOMAIN_POLICY, O_RDWR); |
539 |
} |
540 |
if (ccs_query_fd == EOF) { |
541 |
fprintf(stderr, |
542 |
"You can't run this utility for this kernel.\n"); |
543 |
return 1; |
544 |
} else if (!ccs_network_mode && write(ccs_query_fd, "", 0) != 0) { |
545 |
fprintf(stderr, "You need to register this program to %s to " |
546 |
"run this program.\n", CCS_PROC_POLICY_MANAGER); |
547 |
return 1; |
548 |
} |
549 |
if (ccs_check_update != CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE) { |
550 |
socketpair(AF_UNIX, SOCK_DGRAM, 0, pipe_fd); |
551 |
switch (fork()) { |
552 |
case 0: |
553 |
if (ccs_domain_fp) |
554 |
fclose(ccs_domain_fp); |
555 |
else |
556 |
close(ccs_domain_policy_fd); |
557 |
close(ccs_query_fd); |
558 |
close(pipe_fd[0]); |
559 |
ccs_do_check_update(pipe_fd[1]); |
560 |
_exit(0); |
561 |
case -1: |
562 |
fprintf(stderr, "Can't fork().\n"); |
563 |
return 1; |
564 |
} |
565 |
close(pipe_fd[1]); |
566 |
pipe_fd[1] = EOF; |
567 |
} |
568 |
ccs_readline_history = malloc(CCS_MAX_READLINE_HISTORY * sizeof(const char *)); |
569 |
if (!ccs_readline_history) |
570 |
ccs_out_of_memory(); |
571 |
ccs_send_keepalive(); |
572 |
initscr(); |
573 |
cbreak(); |
574 |
noecho(); |
575 |
nonl(); |
576 |
intrflush(stdscr, FALSE); |
577 |
keypad(stdscr, TRUE); |
578 |
clear(); |
579 |
refresh(); |
580 |
scrollok(stdscr, TRUE); |
581 |
if (ccs_network_mode) { |
582 |
const u32 ip = ntohl(ccs_network_ip); |
583 |
ccs_printw("Monitoring /proc/ccs/query via %u.%u.%u.%u:%u.", |
584 |
(u8) (ip >> 24), (u8) (ip >> 16), (u8) (ip >> 8), |
585 |
(u8) ip, ntohs(ccs_network_port)); |
586 |
} else |
587 |
ccs_printw("Monitoring /proc/ccs/query %s.", |
588 |
ccs_check_update != CCS_GLOBALLY_READABLE_FILES_UPDATE_NONE ? |
589 |
"and /etc/ld.so.cache " : ""); |
590 |
ccs_printw(" Press Ctrl-C to terminate.\n\n"); |
591 |
while (true) { |
592 |
static _Bool first = true; |
593 |
static unsigned int prev_serial = 0; |
594 |
fd_set rfds; |
595 |
unsigned int serial; |
596 |
char *cp; |
597 |
if (!ccs_buffer) { |
598 |
ccs_buffer = malloc(ccs_buffer_len); |
599 |
if (!ccs_buffer) |
600 |
break; |
601 |
} |
602 |
/* Wait for query. */ |
603 |
if (ccs_network_mode) { |
604 |
int i; |
605 |
write(ccs_query_fd, "", 1); |
606 |
memset(ccs_buffer, 0, ccs_buffer_len); |
607 |
for (i = 0; i < ccs_buffer_len - 1; i++) { |
608 |
if (read(ccs_query_fd, ccs_buffer + i, 1) != 1) |
609 |
break; |
610 |
if (!ccs_buffer[i]) |
611 |
goto read_ok; |
612 |
} |
613 |
break; |
614 |
} |
615 |
FD_ZERO(&rfds); |
616 |
FD_SET(ccs_query_fd, &rfds); |
617 |
if (pipe_fd[0] != EOF) |
618 |
FD_SET(pipe_fd[0], &rfds); |
619 |
select(ccs_query_fd > pipe_fd[0] ? ccs_query_fd + 1 : pipe_fd[0] + 1, |
620 |
&rfds, NULL, NULL, NULL); |
621 |
if (pipe_fd[0] != EOF && FD_ISSET(pipe_fd[0], &rfds)) |
622 |
ccs_handle_update(ccs_check_update, pipe_fd[0]); |
623 |
if (!FD_ISSET(ccs_query_fd, &rfds)) |
624 |
continue; |
625 |
|
626 |
/* Read query. */ |
627 |
memset(ccs_buffer, 0, ccs_buffer_len); |
628 |
if (read(ccs_query_fd, ccs_buffer, ccs_buffer_len - 1) <= 0) |
629 |
continue; |
630 |
read_ok: |
631 |
cp = strchr(ccs_buffer, '\n'); |
632 |
if (!cp) |
633 |
continue; |
634 |
*cp = '\0'; |
635 |
|
636 |
/* Get query number. */ |
637 |
if (sscanf(ccs_buffer, "Q%u-%hu", &serial, &ccs_retries) != 2) |
638 |
continue; |
639 |
memmove(ccs_buffer, cp + 1, strlen(cp + 1) + 1); |
640 |
|
641 |
first = false; |
642 |
prev_serial = serial; |
643 |
/* Clear pending input. */; |
644 |
timeout(0); |
645 |
while (true) { |
646 |
int c = ccs_getch2(); |
647 |
if (c == EOF || c == ERR) |
648 |
break; |
649 |
} |
650 |
timeout(1000); |
651 |
if (ccs_handle_query(serial)) |
652 |
continue; |
653 |
break; |
654 |
} |
655 |
endwin(); |
656 |
return 0; |
657 |
} |