This source file includes following definitions.
- curses_free_priv
- curses_init
- curses_finish
- curses_reset
- curses_subprocess_output
- curses_ver
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- curses_output_xml
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- curses_increment_list
- curses_end_list
- curses_is_quiet
- curses_spacer
- curses_progress
- curses_prompt
- crm_mon_mk_curses_output
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- PCMK__OUTPUT_ARGS
- crm_mon_register_messages
- blank_screen
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <stdarg.h>
12 #include <stdint.h>
13 #include <stdlib.h>
14 #include <crm/crm.h>
15 #include <crm/stonith-ng.h>
16 #include <crm/fencing/internal.h>
17 #include <crm/pengine/internal.h>
18 #include <glib.h>
19 #include <pacemaker-internal.h>
20
21 #include "crm_mon.h"
22
23 #if CURSES_ENABLED
24
25 GOptionEntry crm_mon_curses_output_entries[] = {
26 { NULL }
27 };
28
29 typedef struct curses_list_data_s {
30 unsigned int len;
31 char *singular_noun;
32 char *plural_noun;
33 } curses_list_data_t;
34
35 typedef struct private_data_s {
36 GQueue *parent_q;
37 } private_data_t;
38
39 static void
40 curses_free_priv(pcmk__output_t *out) {
41 private_data_t *priv = out->priv;
42
43 if (priv == NULL) {
44 return;
45 }
46
47 g_queue_free(priv->parent_q);
48 free(priv);
49 out->priv = NULL;
50 }
51
52 static bool
53 curses_init(pcmk__output_t *out) {
54 private_data_t *priv = NULL;
55
56
57 if (out->priv != NULL) {
58 return true;
59 } else {
60 out->priv = calloc(1, sizeof(private_data_t));
61 if (out->priv == NULL) {
62 return false;
63 }
64
65 priv = out->priv;
66 }
67
68 priv->parent_q = g_queue_new();
69
70 initscr();
71 cbreak();
72 noecho();
73
74 return true;
75 }
76
77 static void
78 curses_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest) {
79 CRM_ASSERT(out != NULL);
80
81 echo();
82 nocbreak();
83 endwin();
84 }
85
86 static void
87 curses_reset(pcmk__output_t *out) {
88 CRM_ASSERT(out != NULL);
89
90 curses_free_priv(out);
91 curses_init(out);
92 }
93
94 static void
95 curses_subprocess_output(pcmk__output_t *out, int exit_status,
96 const char *proc_stdout, const char *proc_stderr) {
97 CRM_ASSERT(out != NULL);
98
99 if (proc_stdout != NULL) {
100 printw("%s\n", proc_stdout);
101 }
102
103 if (proc_stderr != NULL) {
104 printw("%s\n", proc_stderr);
105 }
106
107 clrtoeol();
108 refresh();
109 }
110
111
112
113
114 static void
115 curses_ver(pcmk__output_t *out, bool extended) {
116 CRM_ASSERT(out != NULL);
117
118 if (extended) {
119 printf("Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
120 } else {
121 printf("Pacemaker %s\n", PACEMAKER_VERSION);
122 printf("Written by Andrew Beekhof and the "
123 "Pacemaker project contributors\n");
124 }
125 }
126
127 G_GNUC_PRINTF(2, 3)
128 static void
129 curses_error(pcmk__output_t *out, const char *format, ...) {
130 va_list ap;
131
132 CRM_ASSERT(out != NULL);
133
134
135
136
137 va_start(ap, format);
138 vw_printw(stdscr, format, ap);
139 va_end(ap);
140
141
142 addch('\n');
143
144 clrtoeol();
145 refresh();
146 sleep(2);
147 }
148
149 G_GNUC_PRINTF(2, 3)
150 static int
151 curses_info(pcmk__output_t *out, const char *format, ...) {
152 va_list ap;
153
154 CRM_ASSERT(out != NULL);
155
156 if (out->is_quiet(out)) {
157 return pcmk_rc_no_output;
158 }
159
160
161
162
163 va_start(ap, format);
164 vw_printw(stdscr, format, ap);
165 va_end(ap);
166
167
168 addch('\n');
169
170 clrtoeol();
171 refresh();
172 return pcmk_rc_ok;
173 }
174
175 static void
176 curses_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
177 CRM_ASSERT(out != NULL);
178 curses_indented_printf(out, "%s", buf);
179 }
180
181 G_GNUC_PRINTF(4, 5)
182 static void
183 curses_begin_list(pcmk__output_t *out, const char *singular_noun, const char *plural_noun,
184 const char *format, ...) {
185 private_data_t *priv = NULL;
186 curses_list_data_t *new_list = NULL;
187 va_list ap;
188
189 CRM_ASSERT(out != NULL && out->priv != NULL);
190 priv = out->priv;
191
192
193
194
195
196 if (format != NULL) {
197 va_start(ap, format);
198
199 curses_indented_vprintf(out, format, ap);
200 printw(":\n");
201
202 va_end(ap);
203 }
204
205 new_list = calloc(1, sizeof(curses_list_data_t));
206 new_list->len = 0;
207 pcmk__str_update(&new_list->singular_noun, singular_noun);
208 pcmk__str_update(&new_list->plural_noun, plural_noun);
209
210 g_queue_push_tail(priv->parent_q, new_list);
211 }
212
213 G_GNUC_PRINTF(3, 4)
214 static void
215 curses_list_item(pcmk__output_t *out, const char *id, const char *format, ...) {
216 va_list ap;
217
218 CRM_ASSERT(out != NULL);
219
220 va_start(ap, format);
221
222 if (id != NULL) {
223 curses_indented_printf(out, "%s: ", id);
224 vw_printw(stdscr, format, ap);
225 } else {
226 curses_indented_vprintf(out, format, ap);
227 }
228
229 addch('\n');
230 va_end(ap);
231
232 out->increment_list(out);
233 }
234
235 static void
236 curses_increment_list(pcmk__output_t *out) {
237 private_data_t *priv = NULL;
238 gpointer tail;
239
240 CRM_ASSERT(out != NULL && out->priv != NULL);
241 priv = out->priv;
242
243 tail = g_queue_peek_tail(priv->parent_q);
244 CRM_ASSERT(tail != NULL);
245 ((curses_list_data_t *) tail)->len++;
246 }
247
248 static void
249 curses_end_list(pcmk__output_t *out) {
250 private_data_t *priv = NULL;
251 curses_list_data_t *node = NULL;
252
253 CRM_ASSERT(out != NULL && out->priv != NULL);
254 priv = out->priv;
255
256 node = g_queue_pop_tail(priv->parent_q);
257
258 if (node->singular_noun != NULL && node->plural_noun != NULL) {
259 if (node->len == 1) {
260 curses_indented_printf(out, "%d %s found\n", node->len, node->singular_noun);
261 } else {
262 curses_indented_printf(out, "%d %s found\n", node->len, node->plural_noun);
263 }
264 }
265
266 free(node);
267 }
268
269 static bool
270 curses_is_quiet(pcmk__output_t *out) {
271 CRM_ASSERT(out != NULL);
272 return out->quiet;
273 }
274
275 static void
276 curses_spacer(pcmk__output_t *out) {
277 CRM_ASSERT(out != NULL);
278 addch('\n');
279 }
280
281 static void
282 curses_progress(pcmk__output_t *out, bool end) {
283 CRM_ASSERT(out != NULL);
284
285 if (end) {
286 printw(".\n");
287 } else {
288 addch('.');
289 }
290 }
291
292 static void
293 curses_prompt(const char *prompt, bool do_echo, char **dest)
294 {
295 int rc = OK;
296
297 CRM_ASSERT(prompt != NULL);
298 CRM_ASSERT(dest != NULL);
299
300
301
302
303
304 if (do_echo) {
305 rc = echo();
306 }
307
308 if (rc == OK) {
309 printw("%s: ", prompt);
310
311 if (*dest != NULL) {
312 free(*dest);
313 }
314
315 *dest = calloc(1, 1024);
316
317
318
319
320 rc = scanw((NCURSES_CONST char *) "%1023s", *dest);
321 addch('\n');
322 }
323
324 if (rc < 1) {
325 free(*dest);
326 *dest = NULL;
327 }
328
329 if (do_echo) {
330 noecho();
331 }
332 }
333
334 pcmk__output_t *
335 crm_mon_mk_curses_output(char **argv) {
336 pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
337
338 if (retval == NULL) {
339 return NULL;
340 }
341
342 retval->fmt_name = "console";
343 retval->request = argv == NULL ? NULL : g_strjoinv(" ", argv);
344
345 retval->init = curses_init;
346 retval->free_priv = curses_free_priv;
347 retval->finish = curses_finish;
348 retval->reset = curses_reset;
349
350 retval->register_message = pcmk__register_message;
351 retval->message = pcmk__call_message;
352
353 retval->subprocess_output = curses_subprocess_output;
354 retval->version = curses_ver;
355 retval->err = curses_error;
356 retval->info = curses_info;
357 retval->output_xml = curses_output_xml;
358
359 retval->begin_list = curses_begin_list;
360 retval->list_item = curses_list_item;
361 retval->increment_list = curses_increment_list;
362 retval->end_list = curses_end_list;
363
364 retval->is_quiet = curses_is_quiet;
365 retval->spacer = curses_spacer;
366 retval->progress = curses_progress;
367 retval->prompt = curses_prompt;
368
369 return retval;
370 }
371
372 G_GNUC_PRINTF(2, 0)
373 void
374 curses_formatted_vprintf(pcmk__output_t *out, const char *format, va_list args) {
375 vw_printw(stdscr, format, args);
376
377 clrtoeol();
378 refresh();
379 }
380
381 G_GNUC_PRINTF(2, 3)
382 void
383 curses_formatted_printf(pcmk__output_t *out, const char *format, ...) {
384 va_list ap;
385
386 va_start(ap, format);
387 curses_formatted_vprintf(out, format, ap);
388 va_end(ap);
389 }
390
391 G_GNUC_PRINTF(2, 0)
392 void
393 curses_indented_vprintf(pcmk__output_t *out, const char *format, va_list args) {
394 int level = 0;
395 private_data_t *priv = out->priv;
396
397 CRM_ASSERT(priv != NULL);
398
399 level = g_queue_get_length(priv->parent_q);
400
401 for (int i = 0; i < level; i++) {
402 printw(" ");
403 }
404
405 if (level > 0) {
406 printw("* ");
407 }
408
409 curses_formatted_vprintf(out, format, args);
410 }
411
412 G_GNUC_PRINTF(2, 3)
413 void
414 curses_indented_printf(pcmk__output_t *out, const char *format, ...) {
415 va_list ap;
416
417 va_start(ap, format);
418 curses_indented_vprintf(out, format, ap);
419 va_end(ap);
420 }
421
422 PCMK__OUTPUT_ARGS("maint-mode", "unsigned long long int")
423 static int
424 cluster_maint_mode_console(pcmk__output_t *out, va_list args) {
425 unsigned long long flags = va_arg(args, unsigned long long);
426
427 if (pcmk_is_set(flags, pe_flag_maintenance_mode)) {
428 curses_formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
429 curses_formatted_printf(out, " The cluster will not attempt to start, stop or recover services\n");
430 return pcmk_rc_ok;
431 } else if (pcmk_is_set(flags, pe_flag_stop_everything)) {
432 curses_formatted_printf(out, "\n *** Resource management is DISABLED ***\n");
433 curses_formatted_printf(out, " The cluster will keep all resources stopped\n");
434 return pcmk_rc_ok;
435 } else {
436 return pcmk_rc_no_output;
437 }
438 }
439
440 PCMK__OUTPUT_ARGS("cluster-status", "pe_working_set_t *", "crm_exit_t",
441 "stonith_history_t *", "gboolean", "uint32_t", "uint32_t",
442 "const char *", "GList *", "GList *")
443 static int
444 cluster_status_console(pcmk__output_t *out, va_list args) {
445 int rc = pcmk_rc_no_output;
446
447 blank_screen();
448 rc = pcmk__cluster_status_text(out, args);
449 refresh();
450 return rc;
451 }
452
453 PCMK__OUTPUT_ARGS("stonith-event", "stonith_history_t *", "gboolean", "gboolean")
454 static int
455 stonith_event_console(pcmk__output_t *out, va_list args) {
456 stonith_history_t *event = va_arg(args, stonith_history_t *);
457 gboolean full_history = va_arg(args, gboolean);
458 gboolean later_succeeded = va_arg(args, gboolean);
459
460 crm_time_t *crm_when = crm_time_new(NULL);
461 char *buf = NULL;
462
463 crm_time_set_timet(crm_when, &(event->completed));
464 buf = crm_time_as_string(crm_when, crm_time_log_date | crm_time_log_timeofday | crm_time_log_with_timezone);
465
466 switch (event->state) {
467 case st_failed:
468 curses_indented_printf(out,
469 "%s of %s failed%s%s%s: "
470 "delegate=%s, client=%s, origin=%s, %s='%s' %s\n",
471 stonith_action_str(event->action), event->target,
472 (event->exit_reason == NULL)? "" : " (",
473 (event->exit_reason == NULL)? "" : event->exit_reason,
474 (event->exit_reason == NULL)? "" : ")",
475 event->delegate ? event->delegate : "",
476 event->client, event->origin,
477 full_history ? "completed" : "last-failed", buf,
478 later_succeeded ? " (a later attempt succeeded)" : "");
479 break;
480
481 case st_done:
482 curses_indented_printf(out, "%s of %s successful: delegate=%s, client=%s, origin=%s, %s='%s'\n",
483 stonith_action_str(event->action), event->target,
484 event->delegate ? event->delegate : "",
485 event->client, event->origin,
486 full_history ? "completed" : "last-successful", buf);
487 break;
488
489 default:
490 curses_indented_printf(out, "%s of %s pending: client=%s, origin=%s\n",
491 stonith_action_str(event->action), event->target,
492 event->client, event->origin);
493 break;
494 }
495
496 free(buf);
497 crm_time_free(crm_when);
498 return pcmk_rc_ok;
499 }
500
501 static pcmk__message_entry_t fmt_functions[] = {
502 { "cluster-status", "console", cluster_status_console },
503 { "maint-mode", "console", cluster_maint_mode_console },
504 { "stonith-event", "console", stonith_event_console },
505
506 { NULL, NULL, NULL }
507 };
508
509 #endif
510
511 void
512 crm_mon_register_messages(pcmk__output_t *out) {
513 #if CURSES_ENABLED
514 pcmk__register_messages(out, fmt_functions);
515 #endif
516 }
517
518 void
519 blank_screen(void)
520 {
521 #if CURSES_ENABLED
522 int lpc = 0;
523
524 for (lpc = 0; lpc < LINES; lpc++) {
525 move(lpc, 0);
526 clrtoeol();
527 }
528 move(0, 0);
529 refresh();
530 #endif
531 }