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