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