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
- 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 static void
170 text_output_xml(pcmk__output_t *out, const char *name, const char *buf) {
171 CRM_ASSERT(out != NULL);
172 pcmk__indented_printf(out, "%s", buf);
173 }
174
175 G_GNUC_PRINTF(4, 5)
176 static void
177 text_begin_list(pcmk__output_t *out, const char *singular_noun, const char *plural_noun,
178 const char *format, ...) {
179 private_data_t *priv = NULL;
180 text_list_data_t *new_list = NULL;
181 va_list ap;
182
183 CRM_ASSERT(out != NULL && out->priv != NULL);
184 priv = out->priv;
185
186 va_start(ap, format);
187
188 if (fancy && format) {
189 pcmk__indented_vprintf(out, format, ap);
190 fprintf(out->dest, ":\n");
191 }
192
193 va_end(ap);
194
195 new_list = calloc(1, sizeof(text_list_data_t));
196 new_list->len = 0;
197 pcmk__str_update(&new_list->singular_noun, singular_noun);
198 pcmk__str_update(&new_list->plural_noun, plural_noun);
199
200 g_queue_push_tail(priv->parent_q, new_list);
201 }
202
203 G_GNUC_PRINTF(3, 4)
204 static void
205 text_list_item(pcmk__output_t *out, const char *id, const char *format, ...) {
206 va_list ap;
207
208 CRM_ASSERT(out != NULL);
209
210 va_start(ap, format);
211
212 if (fancy) {
213 if (id != NULL) {
214
215
216
217
218 pcmk__indented_printf(out, "%s: ", id);
219 vfprintf(out->dest, format, ap);
220 } else {
221 pcmk__indented_vprintf(out, format, ap);
222 }
223 } else {
224 pcmk__indented_vprintf(out, format, ap);
225 }
226
227 fputc('\n', out->dest);
228 fflush(out->dest);
229 va_end(ap);
230
231 out->increment_list(out);
232 }
233
234 static void
235 text_increment_list(pcmk__output_t *out) {
236 private_data_t *priv = NULL;
237 gpointer tail;
238
239 CRM_ASSERT(out != NULL && out->priv != NULL);
240 priv = out->priv;
241
242 tail = g_queue_peek_tail(priv->parent_q);
243 CRM_ASSERT(tail != NULL);
244 ((text_list_data_t *) tail)->len++;
245 }
246
247 static void
248 text_end_list(pcmk__output_t *out) {
249 private_data_t *priv = NULL;
250 text_list_data_t *node = NULL;
251
252 CRM_ASSERT(out != NULL && out->priv != NULL);
253 priv = out->priv;
254
255 node = g_queue_pop_tail(priv->parent_q);
256
257 if (node->singular_noun != NULL && node->plural_noun != NULL) {
258 if (node->len == 1) {
259 pcmk__indented_printf(out, "%d %s found\n", node->len, node->singular_noun);
260 } else {
261 pcmk__indented_printf(out, "%d %s found\n", node->len, node->plural_noun);
262 }
263 }
264
265 free(node);
266 }
267
268 static bool
269 text_is_quiet(pcmk__output_t *out) {
270 CRM_ASSERT(out != NULL);
271 return out->quiet;
272 }
273
274 static void
275 text_spacer(pcmk__output_t *out) {
276 CRM_ASSERT(out != NULL);
277 fprintf(out->dest, "\n");
278 }
279
280 static void
281 text_progress(pcmk__output_t *out, bool end) {
282 CRM_ASSERT(out != NULL);
283
284 if (out->dest == stdout) {
285 fprintf(out->dest, ".");
286
287 if (end) {
288 fprintf(out->dest, "\n");
289 }
290 }
291 }
292
293 pcmk__output_t *
294 pcmk__mk_text_output(char **argv) {
295 pcmk__output_t *retval = calloc(1, sizeof(pcmk__output_t));
296
297 if (retval == NULL) {
298 return NULL;
299 }
300
301 retval->fmt_name = "text";
302 retval->request = pcmk__quote_cmdline(argv);
303
304 retval->init = text_init;
305 retval->free_priv = text_free_priv;
306 retval->finish = text_finish;
307 retval->reset = text_reset;
308
309 retval->register_message = pcmk__register_message;
310 retval->message = pcmk__call_message;
311
312 retval->subprocess_output = text_subprocess_output;
313 retval->version = text_version;
314 retval->info = text_info;
315 retval->err = text_err;
316 retval->output_xml = text_output_xml;
317
318 retval->begin_list = text_begin_list;
319 retval->list_item = text_list_item;
320 retval->increment_list = text_increment_list;
321 retval->end_list = text_end_list;
322
323 retval->is_quiet = text_is_quiet;
324 retval->spacer = text_spacer;
325 retval->progress = text_progress;
326 retval->prompt = pcmk__text_prompt;
327
328 return retval;
329 }
330
331 G_GNUC_PRINTF(2, 0)
332 void
333 pcmk__formatted_vprintf(pcmk__output_t *out, const char *format, va_list args) {
334 int len = 0;
335
336 CRM_ASSERT(out != NULL);
337 CRM_CHECK(pcmk__str_eq(out->fmt_name, "text", pcmk__str_none), return);
338
339 len = vfprintf(out->dest, format, args);
340 CRM_ASSERT(len >= 0);
341 }
342
343 G_GNUC_PRINTF(2, 3)
344 void
345 pcmk__formatted_printf(pcmk__output_t *out, const char *format, ...) {
346 va_list ap;
347
348 CRM_ASSERT(out != NULL);
349
350 va_start(ap, format);
351 pcmk__formatted_vprintf(out, format, ap);
352 va_end(ap);
353 }
354
355 G_GNUC_PRINTF(2, 0)
356 void
357 pcmk__indented_vprintf(pcmk__output_t *out, const char *format, va_list args) {
358 CRM_ASSERT(out != NULL);
359 CRM_CHECK(pcmk__str_eq(out->fmt_name, "text", pcmk__str_none), return);
360
361 if (fancy) {
362 int level = 0;
363 private_data_t *priv = out->priv;
364
365 CRM_ASSERT(priv != NULL);
366
367 level = g_queue_get_length(priv->parent_q);
368
369 for (int i = 0; i < level; i++) {
370 fprintf(out->dest, " ");
371 }
372
373 if (level > 0) {
374 fprintf(out->dest, "* ");
375 }
376 }
377
378 pcmk__formatted_vprintf(out, format, args);
379 }
380
381 G_GNUC_PRINTF(2, 3)
382 void
383 pcmk__indented_printf(pcmk__output_t *out, const char *format, ...) {
384 va_list ap;
385
386 CRM_ASSERT(out != NULL);
387
388 va_start(ap, format);
389 pcmk__indented_vprintf(out, format, ap);
390 va_end(ap);
391 }
392
393 void
394 pcmk__text_prompt(const char *prompt, bool echo, char **dest)
395 {
396 int rc = 0;
397 struct termios settings;
398 tcflag_t orig_c_lflag = 0;
399
400 CRM_ASSERT(prompt != NULL);
401 CRM_ASSERT(dest != NULL);
402
403 if (!echo) {
404 rc = tcgetattr(0, &settings);
405 if (rc == 0) {
406 orig_c_lflag = settings.c_lflag;
407 settings.c_lflag &= ~ECHO;
408 rc = tcsetattr(0, TCSANOW, &settings);
409 }
410 }
411
412 if (rc == 0) {
413 fprintf(stderr, "%s: ", prompt);
414
415 if (*dest != NULL) {
416 free(*dest);
417 *dest = NULL;
418 }
419
420 #if HAVE_SSCANF_M
421 rc = scanf("%ms", dest);
422 #else
423 *dest = calloc(1, 1024);
424 rc = scanf("%1023s", *dest);
425 #endif
426 fprintf(stderr, "\n");
427 }
428
429 if (rc < 1) {
430 free(*dest);
431 *dest = NULL;
432 }
433
434 if (orig_c_lflag != 0) {
435 settings.c_lflag = orig_c_lflag;
436 tcsetattr(0, TCSANOW, &settings);
437 }
438 }