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