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