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