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