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