This source file includes following definitions.
- free_list_data
- text_free_priv
- text_init
- text_finish
- text_reset
- text_subprocess_output
- text_version
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- text_output_xml
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- text_increment_list
- text_end_list
- text_is_quiet
- text_spacer
- text_progress
- pcmk__mk_text_output
- pcmk__output_text_get_fancy
- pcmk__output_text_set_fancy
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- G_GNUC_PRINTF
- pcmk__text_prompt
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11 #include <crm/common/cmdline_internal.h>
12
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #include <glib.h>
16 #include <termios.h>
17
18 #include "crmcommon_private.h"
19
20
21 static gboolean fancy = FALSE;
22
23
24 GOptionEntry pcmk__text_output_entries[] = {
25 { "text-fancy", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &fancy,
26 "Use more highly formatted output (requires --output-as=text)",
27 NULL },
28
29 { NULL }
30 };
31
32 typedef struct text_list_data_s {
33 unsigned int len;
34 char *singular_noun;
35 char *plural_noun;
36 } text_list_data_t;
37
38 typedef struct private_data_s {
39 GQueue *parent_q;
40 bool fancy;
41 } private_data_t;
42
43 static void
44 free_list_data(gpointer data) {
45 text_list_data_t *list_data = data;
46
47 free(list_data->singular_noun);
48 free(list_data->plural_noun);
49 }
50
51 static void
52 text_free_priv(pcmk__output_t *out) {
53 private_data_t *priv = NULL;
54
55 if (out == NULL || out->priv == NULL) {
56 return;
57 }
58
59 priv = out->priv;
60
61 g_queue_free_full(priv->parent_q, free_list_data);
62 free(priv);
63 out->priv = NULL;
64 }
65
66 static bool
67 text_init(pcmk__output_t *out) {
68 private_data_t *priv = NULL;
69
70 pcmk__assert(out != NULL);
71
72
73 if (out->priv != NULL) {
74 return true;
75 }
76
77 out->priv = calloc(1, sizeof(private_data_t));
78 if (out->priv == NULL) {
79 return false;
80 }
81
82 priv = out->priv;
83 priv->parent_q = g_queue_new();
84 return true;
85 }
86
87 static void
88 text_finish(pcmk__output_t *out, crm_exit_t exit_status, bool print, void **copy_dest)
89 {
90 pcmk__assert((out != NULL) && (out->dest != NULL));
91 fflush(out->dest);
92 }
93
94 static void
95 text_reset(pcmk__output_t *out) {
96 private_data_t *priv = NULL;
97 bool old_fancy = false;
98
99 pcmk__assert(out != NULL);
100
101 if (out->dest != stdout) {
102 out->dest = freopen(NULL, "w", out->dest);
103 }
104
105 pcmk__assert(out->dest != NULL);
106
107
108 priv = out->priv;
109 old_fancy = priv->fancy;
110
111 text_free_priv(out);
112 text_init(out);
113
114 priv = out->priv;
115 priv->fancy = old_fancy;
116 }
117
118 static void
119 text_subprocess_output(pcmk__output_t *out, int exit_status,
120 const char *proc_stdout, const char *proc_stderr) {
121 pcmk__assert(out != NULL);
122
123 if (proc_stdout != NULL) {
124 fprintf(out->dest, "%s\n", proc_stdout);
125 }
126
127 if (proc_stderr != NULL) {
128 fprintf(out->dest, "%s\n", proc_stderr);
129 }
130 }
131
132 static void
133 text_version(pcmk__output_t *out, bool extended)
134 {
135 pcmk__assert((out != NULL) && (out->dest != NULL));
136
137 if (extended) {
138 fprintf(out->dest, "Pacemaker %s (Build: %s): %s\n", PACEMAKER_VERSION, BUILD_VERSION, CRM_FEATURES);
139 } else {
140 fprintf(out->dest, "Pacemaker %s\n", PACEMAKER_VERSION);
141 fprintf(out->dest, "Written by Andrew Beekhof and "
142 "the Pacemaker project contributors\n");
143 }
144 }
145
146 G_GNUC_PRINTF(2, 3)
147 static void
148 text_err(pcmk__output_t *out, const char *format, ...) {
149 va_list ap;
150
151 pcmk__assert(out != NULL);
152
153 va_start(ap, format);
154
155
156
157
158 vfprintf(stderr, format, ap);
159 va_end(ap);
160
161
162 fprintf(stderr, "\n");
163 }
164
165 G_GNUC_PRINTF(2, 3)
166 static int
167 text_info(pcmk__output_t *out, const char *format, ...) {
168 va_list ap;
169
170 pcmk__assert(out != NULL);
171
172 if (out->is_quiet(out)) {
173 return pcmk_rc_no_output;
174 }
175
176 va_start(ap, format);
177
178
179
180
181 vfprintf(out->dest, format, ap);
182 va_end(ap);
183
184
185 fprintf(out->dest, "\n");
186 return pcmk_rc_ok;
187 }
188
189 G_GNUC_PRINTF(2, 3)
190 static int
191 text_transient(pcmk__output_t *out, const char *format, ...)
192 {
193 return pcmk_rc_no_output;
194 }
195
196 static void
197 text_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
198 pcmk__assert(out != NULL);
199 pcmk__indented_printf(out, "%s", buf);
200 }
201
202 G_GNUC_PRINTF(4, 5)
203 static void
204 text_begin_list(pcmk__output_t *out, const char *singular_noun, const char *plural_noun,
205 const char *format, ...) {
206 private_data_t *priv = NULL;
207 text_list_data_t *new_list = NULL;
208 va_list ap;
209
210 pcmk__assert((out != NULL) && (out->priv != NULL));
211 priv = out->priv;
212
213 va_start(ap, format);
214
215 if ((fancy || priv->fancy) && (format != NULL)) {
216 pcmk__indented_vprintf(out, format, ap);
217 fprintf(out->dest, ":\n");
218 }
219
220 va_end(ap);
221
222 new_list = pcmk__assert_alloc(1, sizeof(text_list_data_t));
223 new_list->len = 0;
224 new_list->singular_noun = pcmk__str_copy(singular_noun);
225 new_list->plural_noun = pcmk__str_copy(plural_noun);
226
227 g_queue_push_tail(priv->parent_q, new_list);
228 }
229
230 G_GNUC_PRINTF(3, 4)
231 static void
232 text_list_item(pcmk__output_t *out, const char *id, const char *format, ...) {
233 private_data_t *priv = NULL;
234 va_list ap;
235
236 pcmk__assert(out != NULL);
237
238 priv = out->priv;
239 va_start(ap, format);
240
241 if (fancy || priv->fancy) {
242 if (id != NULL) {
243
244
245
246
247 pcmk__indented_printf(out, "%s: ", id);
248 vfprintf(out->dest, format, ap);
249 } else {
250 pcmk__indented_vprintf(out, format, ap);
251 }
252 } else {
253 pcmk__indented_vprintf(out, format, ap);
254 }
255
256 fputc('\n', out->dest);
257 fflush(out->dest);
258 va_end(ap);
259
260 out->increment_list(out);
261 }
262
263 static void
264 text_increment_list(pcmk__output_t *out) {
265 private_data_t *priv = NULL;
266 gpointer tail;
267
268 pcmk__assert((out != NULL) && (out->priv != NULL));
269 priv = out->priv;
270
271 tail = g_queue_peek_tail(priv->parent_q);
272 pcmk__assert(tail != NULL);
273 ((text_list_data_t *) tail)->len++;
274 }
275
276 static void
277 text_end_list(pcmk__output_t *out) {
278 private_data_t *priv = NULL;
279 text_list_data_t *node = NULL;
280
281 pcmk__assert((out != NULL) && (out->priv != NULL));
282 priv = out->priv;
283
284 node = g_queue_pop_tail(priv->parent_q);
285
286 if (node->singular_noun != NULL && node->plural_noun != NULL) {
287 if (node->len == 1) {
288 pcmk__indented_printf(out, "%d %s found\n", node->len, node->singular_noun);
289 } else {
290 pcmk__indented_printf(out, "%d %s found\n", node->len, node->plural_noun);
291 }
292 }
293
294 free_list_data(node);
295 }
296
297 static bool
298 text_is_quiet(pcmk__output_t *out) {
299 pcmk__assert(out != NULL);
300 return out->quiet;
301 }
302
303 static void
304 text_spacer(pcmk__output_t *out) {
305 pcmk__assert(out != NULL);
306 fprintf(out->dest, "\n");
307 }
308
309 static void
310 text_progress(pcmk__output_t *out, bool end) {
311 pcmk__assert(out != NULL);
312
313 if (out->dest == stdout) {
314 fprintf(out->dest, ".");
315
316 if (end) {
317 fprintf(out->dest, "\n");
318 }
319 }
320 }
321
322 pcmk__output_t *
323 pcmk__mk_text_output(char **argv) {
324 pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
325
326 if (retval == NULL) {
327 return NULL;
328 }
329
330 retval->fmt_name = "text";
331 retval->request = pcmk__quote_cmdline(argv);
332
333 retval->init = text_init;
334 retval->free_priv = text_free_priv;
335 retval->finish = text_finish;
336 retval->reset = text_reset;
337
338 retval->register_message = pcmk__register_message;
339 retval->message = pcmk__call_message;
340
341 retval->subprocess_output = text_subprocess_output;
342 retval->version = text_version;
343 retval->info = text_info;
344 retval->transient = text_transient;
345 retval->err = text_err;
346 retval->output_xml = text_output_xml;
347
348 retval->begin_list = text_begin_list;
349 retval->list_item = text_list_item;
350 retval->increment_list = text_increment_list;
351 retval->end_list = text_end_list;
352
353 retval->is_quiet = text_is_quiet;
354 retval->spacer = text_spacer;
355 retval->progress = text_progress;
356 retval->prompt = pcmk__text_prompt;
357
358 return retval;
359 }
360
361
362
363
364
365
366
367
368
369
370
371 bool
372 pcmk__output_text_get_fancy(pcmk__output_t *out)
373 {
374 pcmk__assert(out != NULL);
375
376 if (pcmk__str_eq(out->fmt_name, "text", pcmk__str_none)) {
377 private_data_t *priv = out->priv;
378
379 pcmk__assert(priv != NULL);
380 return priv->fancy;
381 }
382 return false;
383 }
384
385
386
387
388
389
390
391
392
393
394 void
395 pcmk__output_text_set_fancy(pcmk__output_t *out, bool enabled)
396 {
397 pcmk__assert(out != NULL);
398
399 if (pcmk__str_eq(out->fmt_name, "text", pcmk__str_none)) {
400 private_data_t *priv = out->priv;
401
402 pcmk__assert(priv != NULL);
403 priv->fancy = enabled;
404 }
405 }
406
407 G_GNUC_PRINTF(2, 0)
408 void
409 pcmk__formatted_vprintf(pcmk__output_t *out, const char *format, va_list args) {
410 pcmk__assert(out != NULL);
411 CRM_CHECK(pcmk__str_eq(out->fmt_name, "text", pcmk__str_none), return);
412 vfprintf(out->dest, format, args);
413 }
414
415 G_GNUC_PRINTF(2, 3)
416 void
417 pcmk__formatted_printf(pcmk__output_t *out, const char *format, ...) {
418 va_list ap;
419
420 pcmk__assert(out != NULL);
421
422 va_start(ap, format);
423 pcmk__formatted_vprintf(out, format, ap);
424 va_end(ap);
425 }
426
427 G_GNUC_PRINTF(2, 0)
428 void
429 pcmk__indented_vprintf(pcmk__output_t *out, const char *format, va_list args) {
430 private_data_t *priv = NULL;
431
432 pcmk__assert(out != NULL);
433 CRM_CHECK(pcmk__str_eq(out->fmt_name, "text", pcmk__str_none), return);
434
435 priv = out->priv;
436
437 if (fancy || priv->fancy) {
438 int level = 0;
439 private_data_t *priv = out->priv;
440
441 pcmk__assert(priv != NULL);
442
443 level = g_queue_get_length(priv->parent_q);
444
445 for (int i = 0; i < level; i++) {
446 fprintf(out->dest, " ");
447 }
448
449 if (level > 0) {
450 fprintf(out->dest, "* ");
451 }
452 }
453
454 pcmk__formatted_vprintf(out, format, args);
455 }
456
457 G_GNUC_PRINTF(2, 3)
458 void
459 pcmk__indented_printf(pcmk__output_t *out, const char *format, ...) {
460 va_list ap;
461
462 pcmk__assert(out != NULL);
463
464 va_start(ap, format);
465 pcmk__indented_vprintf(out, format, ap);
466 va_end(ap);
467 }
468
469 void
470 pcmk__text_prompt(const char *prompt, bool echo, char **dest)
471 {
472 int rc = 0;
473 struct termios settings;
474 tcflag_t orig_c_lflag = 0;
475
476 pcmk__assert((prompt != NULL) && (dest != NULL));
477
478 if (!echo) {
479 rc = tcgetattr(0, &settings);
480 if (rc == 0) {
481 orig_c_lflag = settings.c_lflag;
482 settings.c_lflag &= ~ECHO;
483 rc = tcsetattr(0, TCSANOW, &settings);
484 }
485 }
486
487 if (rc == 0) {
488 fprintf(stderr, "%s: ", prompt);
489
490 if (*dest != NULL) {
491 free(*dest);
492 *dest = NULL;
493 }
494
495 #if HAVE_SSCANF_M
496 rc = scanf("%ms", dest);
497 #else
498 *dest = pcmk__assert_alloc(1, 1024);
499 rc = scanf("%1023s", *dest);
500 #endif
501 fprintf(stderr, "\n");
502 }
503
504 if (rc < 1) {
505 free(*dest);
506 *dest = NULL;
507 }
508
509 if (orig_c_lflag != 0) {
510 settings.c_lflag = orig_c_lflag;
511 tcsetattr(0, TCSANOW, &settings);
512 }
513 }