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