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