/[baselayout]/trunk/src/libeinfo.c
Gentoo

Contents of /trunk/src/libeinfo.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2650 - (show annotations) (download) (as text)
Tue Apr 24 11:29:19 2007 UTC (7 years, 3 months ago) by uberlord
File MIME type: text/x-csrc
File size: 14527 byte(s)
We now buffer stdout and stderr to a file and flush that when running in parallel. RC_PARALLEL_STARTUP has been renamed to RC_PARALLEL.
1 /*
2 einfo.c
3 Gentoo informational functions
4 Copyright 2007 Gentoo Foundation
5 */
6
7 #include <sys/types.h>
8 #include <sys/ioctl.h>
9 #include <sys/stat.h>
10 #include <errno.h>
11 #include <fcntl.h>
12 #include <limits.h>
13 #include <stdarg.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <syslog.h>
19 #include <unistd.h>
20
21 #include "einfo.h"
22 #include "rc.h"
23 #include "rc-misc.h"
24
25 #include "hidden-visibility.h"
26 hidden_proto(ecolor)
27 hidden_proto(ebegin)
28 hidden_proto(ebeginv)
29 hidden_proto(ebracket)
30 hidden_proto(eend)
31 hidden_proto(eendv)
32 hidden_proto(eerror)
33 hidden_proto(eerrorn)
34 hidden_proto(eerrorx)
35 hidden_proto(eflush)
36 hidden_proto(eclose)
37 hidden_proto(eindent)
38 hidden_proto(eindentv)
39 hidden_proto(einfo)
40 hidden_proto(einfon)
41 hidden_proto(einfov)
42 hidden_proto(einfovn)
43 hidden_proto(eoutdent)
44 hidden_proto(eoutdentv)
45 hidden_proto(ewarn)
46 hidden_proto(ewarnn)
47 hidden_proto(ewarnv)
48 hidden_proto(ewarnvn)
49 hidden_proto(ewarnx)
50 hidden_proto(ewend)
51 hidden_proto(ewendv)
52
53 /* Incase we cannot work out how many columns from ioctl, supply a default */
54 #define DEFAULT_COLS 80
55
56 #define OK "ok"
57 #define NOT_OK "!!"
58
59 #define CHECK_VERBOSE if (! is_env ("RC_VERBOSE", "yes")) return 0
60
61 /* Number of spaces for an indent */
62 #define INDENT_WIDTH 2
63
64 /* How wide can the indent go? */
65 #define INDENT_MAX 40
66
67 #define EBUFFER_LOCK RC_SVCDIR "ebuffer/.lock"
68
69 /* Default colours */
70 #define ECOLOR_GOOD "\033[32;01m"
71 #define ECOLOR_WARN "\033[33;01m"
72 #define ECOLOR_BAD "\033[31;01m"
73 #define ECOLOR_HILITE "\033[36;01m"
74 #define ECOLOR_BRACKET "\033[34;01m"
75 #define ECOLOR_NORMAL "\033[0m"
76 #define ECOLOR_FLUSH "\033[K"
77
78 /* A cheat sheet of colour capable terminals
79 This is taken from DIR_COLORS from GNU coreutils
80 We embed it here as we shouldn't depend on coreutils */
81 static const char *color_terms[] = {
82 "Eterm",
83 "ansi",
84 "color-xterm",
85 "con132x25",
86 "con132x30",
87 "con132x43",
88 "con132x60",
89 "con80x25",
90 "con80x28",
91 "con80x30",
92 "con80x43",
93 "con80x50",
94 "con80x60",
95 "cons25",
96 "console",
97 "cygwin",
98 "dtterm",
99 "gnome",
100 "konsole",
101 "kterm",
102 "linux",
103 "linux-c",
104 "mach-color",
105 "mlterm",
106 "putty",
107 "rxvt",
108 "rxvt-cygwin",
109 "rxvt-cygwin-native",
110 "rxvt-unicode",
111 "screen",
112 "screen-bce",
113 "screen-w",
114 "screen.linux",
115 "vt100",
116 "xterm",
117 "xterm-256color",
118 "xterm-color",
119 "xterm-debian",
120 NULL
121 };
122
123 /* We use this array to save the stdout/stderr fd's for buffering */
124 static int stdfd[2] = {-1, -1};
125 static FILE *ebfp = NULL;
126 static char ebfile[PATH_MAX] = { '\0' };
127
128 static bool is_env (const char *var, const char *val)
129 {
130 char *v;
131
132 if (! var)
133 return (false);
134
135 v = getenv (var);
136 if (! v)
137 return (val ? false : true);
138
139 return (strcasecmp (v, val) ? false : true);
140 }
141
142 static bool colour_terminal (void)
143 {
144 static int in_colour = -1;
145 int i = 0;
146 char *term;
147
148 if (in_colour == 0)
149 return (false);
150 if (in_colour == 1)
151 return (true);
152
153 term = getenv ("TERM");
154 /* If $TERM isn't set then the chances are we're in single user mode */
155 if (! term)
156 return (true);
157
158 while (color_terms[i]) {
159 if (strcmp (color_terms[i], term) == 0) {
160 in_colour = 1;
161 return (true);
162 }
163 i++;
164 }
165
166 in_colour = 0;
167 return (false);
168 }
169
170 static int get_term_columns (void)
171 {
172 #if defined(TIOCGSIZE) /* BSD */
173 struct ttysize ts;
174
175 if (ioctl(0, TIOCGSIZE, &ts) == 0)
176 return (ts.ts_cols);
177 #elif defined(TIOCGWINSZ) /* Linux */
178 struct winsize ws;
179
180 if (ioctl(0, TIOCGWINSZ, &ws) == 0)
181 return (ws.ws_col);
182 #endif
183
184 return (DEFAULT_COLS);
185 }
186
187 void ebuffer (const char *file)
188 {
189 /* Don't ebuffer if we don't have a file or we already are */
190 if (! file || stdfd[0] >= 0 || ! isatty (fileno (stdout)))
191 return;
192
193 /* Save the current fd's */
194 stdfd[0] = dup (fileno (stdout));
195 stdfd[1] = dup (fileno (stderr));
196
197 if (! (ebfp = fopen (file, "w+"))) {
198 fprintf (stderr, "fopen `%s': %s\n", file, strerror (errno));
199 return;
200 }
201
202 snprintf (ebfile, sizeof (ebfile), "%s", file);
203
204 fflush (stdout);
205 fflush (stderr);
206
207 /* Now redirect stdout and stderr */
208 if ((dup2 (fileno (ebfp), fileno (stdout))) < 0)
209 fprintf (stderr, "dup2: %s", strerror (errno));
210 if ((dup2 (fileno (ebfp), fileno (stderr))) < 0)
211 fprintf (stderr, "dup2: %s", strerror (errno));
212
213 /* Store the filename in our environment so scripts can tell if we're
214 * buffering or not */
215 unsetenv ("RC_EBUFFER");
216 setenv ("RC_EBUFFER", file, 1);
217
218 return;
219 }
220
221 static void _eflush (bool reopen)
222 {
223 char buffer[RC_LINEBUFFER];
224 int serrno = errno;
225
226 /* eflush called from an init script? */
227 if (! ebfp) {
228 char *file = getenv ("RC_EBUFFER");
229 if (file)
230 ebfp = fopen (file, "a+");
231 }
232
233 if (! ebfp)
234 return;
235
236 fflush (stdout);
237 fflush (stderr);
238
239 /* Restore stdout and stderr now */
240 if (stdfd[0] >= 0) {
241 dup2 (stdfd[0], fileno (stdout));
242 dup2 (stdfd[1], fileno (stderr));
243 } else {
244 char *tty = getenv ("RC_TTY");
245 if (tty) {
246 freopen (tty, "w+", stdout);
247 dup2 (fileno (stdout), fileno (stderr));
248 }
249 }
250
251 /* Spin until we can lock the ebuffer */
252 while (true) {
253 struct timeval tv;
254 errno = 0;
255 if (mkfifo (EBUFFER_LOCK, 0700) == 0)
256 break;
257 if (errno != EEXIST)
258 eerror ("mkfifo `%s': %s\n", EBUFFER_LOCK, strerror (errno));
259 tv.tv_sec = 0;
260 tv.tv_usec = 20000;
261 select (0, NULL, NULL, NULL, &tv);
262 }
263 errno = serrno;
264
265 /* Dump the file to stdout */
266 memset (buffer, 0, RC_LINEBUFFER);
267 if (fseek (ebfp, (off_t) 0, SEEK_SET) < 0)
268 eerror ("fseek: %s", strerror (errno));
269 else {
270 while (fgets (buffer, RC_LINEBUFFER, ebfp))
271 printf ("%s", buffer);
272 }
273 fflush (stdout);
274 fflush (stderr);
275
276 if (unlink (EBUFFER_LOCK))
277 eerror ("unlink `%s': %s", EBUFFER_LOCK, strerror (errno));
278
279 if (reopen) {
280 ftruncate (fileno (ebfp), (off_t) 0);
281 fseek (ebfp, (off_t) 0, SEEK_SET);
282 dup2 (fileno (ebfp), fileno (stdout));
283 dup2 (fileno (ebfp), fileno (stderr));
284 } else {
285 stdfd[0] = -1;
286 stdfd[1] = -1;
287 fclose (ebfp);
288 ebfp = NULL;
289 unlink (ebfile);
290 ebfile[0] = '\0';
291 unsetenv ("RC_EBUFFER");
292 }
293
294 return;
295 }
296
297 void eflush () {
298 _eflush (true);
299 }
300 hidden_def(eflush)
301
302 void eclose () {
303 _eflush (false);
304 }
305 hidden_def(eclose)
306
307 static void elog (int level, const char *fmt, va_list ap)
308 {
309 char *e = getenv ("RC_ELOG");
310 va_list apc;
311
312 if (fmt && e) {
313 closelog ();
314 openlog (e, LOG_PID, LOG_DAEMON);
315 va_copy (apc, ap);
316 vsyslog (level, fmt, apc);
317 va_end (apc);
318 closelog ();
319 }
320 }
321
322 static int _eindent (FILE *stream)
323 {
324 char *env = getenv ("RC_EINDENT");
325 int amount = 0;
326 char indent[INDENT_MAX];
327
328 if (env) {
329 errno = 0;
330 amount = strtol (env, NULL, 0);
331 if (errno != 0 || amount < 0)
332 amount = 0;
333 else if (amount > INDENT_MAX)
334 amount = INDENT_MAX;
335
336 if (amount > 0)
337 memset (indent, ' ', amount);
338 }
339
340 /* Terminate it */
341 memset (indent + amount, 0, 1);
342 return (fprintf (stream, "%s", indent));
343 }
344
345 const char *ecolor (einfo_color_t color) {
346 const char *col = NULL;
347
348 if (! colour_terminal ())
349 return ("");
350
351 switch (color) {
352 case ecolor_good:
353 if (! (col = getenv ("ECOLOR_GOOD")))
354 col = ECOLOR_GOOD;
355 break;
356 case ecolor_warn:
357 if (! (col = getenv ("ECOLOR_WARN")))
358 col = ECOLOR_WARN;
359 break;
360 case ecolor_bad:
361 if (! (col = getenv ("ECOLOR_BAD")))
362 col = ECOLOR_BAD;
363 break;
364 case ecolor_hilite:
365 if (! (col = getenv ("ECOLOR_HILITE")))
366 col = ECOLOR_HILITE;
367 break;
368 case ecolor_bracket:
369 if (! (col = getenv ("ECOLOR_BRACKET")))
370 col = ECOLOR_BRACKET;
371 break;
372 case ecolor_normal:
373 col = ECOLOR_NORMAL;
374 break;
375 }
376
377 return (col);
378 }
379 hidden_def(ecolor)
380
381 #define EINFOVN(_file, _color) \
382 fprintf (_file, " %s*%s ", ecolor (_color), ecolor (ecolor_normal)); \
383 retval += _eindent (_file); \
384 { \
385 va_list _ap; \
386 va_copy (_ap, ap); \
387 retval += vfprintf (_file, fmt, _ap) + 3; \
388 va_end (_ap); \
389 } \
390 if (colour_terminal ()) \
391 fprintf (_file, ECOLOR_FLUSH);
392
393 static int _einfovn (const char *fmt, va_list ap)
394 {
395 int retval = 0;
396
397 EINFOVN (stdout, ecolor_good);
398 return (retval);
399 }
400
401 static int _ewarnvn (const char *fmt, va_list ap)
402 {
403 int retval = 0;
404
405 EINFOVN (stdout, ecolor_warn);
406 return (retval);
407 }
408
409 static int _eerrorvn (const char *fmt, va_list ap)
410 {
411 int retval = 0;
412
413 EINFOVN (stderr, ecolor_bad);
414 return (retval);
415 }
416
417 int einfon (const char *fmt, ...)
418 {
419 int retval;
420 va_list ap;
421
422 if (! fmt || is_env ("RC_QUIET", "yes"))
423 return (0);
424
425 va_start (ap, fmt);
426 retval = _einfovn (fmt, ap);
427 va_end (ap);
428
429 return (retval);
430 }
431 hidden_def(einfon)
432
433 int ewarnn (const char *fmt, ...)
434 {
435 int retval;
436 va_list ap;
437
438 if (! fmt || is_env ("RC_QUIET", "yes"))
439 return (0);
440
441 va_start (ap, fmt);
442 retval = _ewarnvn (fmt, ap);
443 va_end (ap);
444
445 return (retval);
446 }
447 hidden_def(ewarnn)
448
449 int eerrorn (const char *fmt, ...)
450 {
451 int retval;
452 va_list ap;
453
454 va_start (ap, fmt);
455 retval = _eerrorvn (fmt, ap);
456 va_end (ap);
457
458 return (retval);
459 }
460 hidden_def(eerrorn)
461
462 int einfo (const char *fmt, ...)
463 {
464 int retval;
465 va_list ap;
466
467 if (! fmt || is_env ("RC_QUIET", "yes"))
468 return (0);
469
470 va_start (ap, fmt);
471 retval = _einfovn (fmt, ap);
472 retval += printf ("\n");
473 va_end (ap);
474
475 return (retval);
476 }
477 hidden_def(einfo)
478
479 int ewarn (const char *fmt, ...)
480 {
481 int retval;
482 va_list ap;
483
484 if (! fmt || is_env ("RC_QUIET", "yes"))
485 return (0);
486
487 va_start (ap, fmt);
488 elog (LOG_WARNING, fmt, ap);
489 retval = _ewarnvn (fmt, ap);
490 retval += printf ("\n");
491 va_end (ap);
492
493 return (retval);
494 }
495 hidden_def(ewarn)
496
497 void ewarnx (const char *fmt, ...)
498 {
499 int retval;
500 va_list ap;
501
502 eclose ();
503 if (fmt && ! is_env ("RC_QUIET", "yes")) {
504 va_start (ap, fmt);
505 elog (LOG_WARNING, fmt, ap);
506 retval = _ewarnvn (fmt, ap);
507 va_end (ap);
508 retval += printf ("\n");
509 }
510 exit (EXIT_FAILURE);
511 }
512 hidden_def(ewarnx)
513
514 int eerror (const char *fmt, ...)
515 {
516 int retval;
517 va_list ap;
518
519 if (! fmt)
520 return (0);
521
522 va_start (ap, fmt);
523 elog (LOG_ERR, fmt, ap);
524 retval = _eerrorvn (fmt, ap);
525 va_end (ap);
526 retval += fprintf (stderr, "\n");
527
528 eflush ();
529 return (retval);
530 }
531 hidden_def(eerror)
532
533 void eerrorx (const char *fmt, ...)
534 {
535 va_list ap;
536
537 eclose ();
538 if (fmt) {
539 va_start (ap, fmt);
540 elog (LOG_ERR, fmt, ap);
541 _eerrorvn (fmt, ap);
542 va_end (ap);
543 printf ("\n");
544 }
545
546 exit (EXIT_FAILURE);
547 }
548 hidden_def(eerrorx)
549
550 int ebegin (const char *fmt, ...)
551 {
552 int retval;
553 va_list ap;
554
555 if (! fmt || is_env ("RC_QUIET", "yes"))
556 return (0);
557
558 va_start (ap, fmt);
559 retval = _einfovn (fmt, ap);
560 va_end (ap);
561 retval += printf (" ...");
562 if (colour_terminal ())
563 retval += printf ("\n");
564
565 return (retval);
566 }
567 hidden_def(ebegin)
568
569 static void _eend (int col, einfo_color_t color, const char *msg)
570 {
571 FILE *fp = stdout;
572 int i;
573 int cols;
574
575 if (! msg)
576 return;
577
578 if (color == ecolor_bad)
579 fp = stderr;
580
581 cols = get_term_columns () - (strlen (msg) + 6);
582
583 if (cols > 0 && colour_terminal ()) {
584 fprintf (fp, "\033[A\033[%dC %s[ %s%s %s]%s\n", cols,
585 ecolor (ecolor_bracket), ecolor (color), msg,
586 ecolor (ecolor_bracket), ecolor (ecolor_normal));
587 } else {
588 for (i = -1; i < cols - col; i++)
589 fprintf (fp, " ");
590 fprintf (fp, "[ %s ]\n", msg);
591 }
592 }
593
594 static int _do_eend (const char *cmd, int retval, const char *fmt, va_list ap)
595 {
596 int col = 0;
597 FILE *fp;
598 va_list apc;
599
600 if (fmt && retval != 0) {
601 va_copy (apc, ap);
602 if (strcmp (cmd, "ewend") == 0) {
603 col = _ewarnvn (fmt, apc);
604 fp = stdout;
605 } else {
606 col = _eerrorvn (fmt, apc);
607 fp = stderr;
608 }
609 va_end (apc);
610 if (colour_terminal ())
611 fprintf (fp, "\n");
612 }
613
614 _eend (col,
615 retval == 0 ? ecolor_good : ecolor_bad,
616 retval == 0 ? OK : NOT_OK);
617 return (retval);
618 }
619
620 int eend (int retval, const char *fmt, ...)
621 {
622 va_list ap;
623
624 if (is_env ("RC_QUIET", "yes"))
625 return (retval);
626
627 va_start (ap, fmt);
628 _do_eend ("eend", retval, fmt, ap);
629 va_end (ap);
630
631 return (retval);
632 }
633 hidden_def(eend)
634
635 int ewend (int retval, const char *fmt, ...)
636 {
637 va_list ap;
638
639 if (is_env ("RC_QUIET", "yes"))
640 return (retval);
641
642 va_start (ap, fmt);
643 _do_eend ("ewend", retval, fmt, ap);
644 va_end (ap);
645
646 return (retval);
647 }
648 hidden_def(ewend)
649
650 void ebracket (int col, einfo_color_t color, const char *msg)
651 {
652 _eend (col, color, msg);
653 }
654 hidden_def(ebracket)
655
656 void eindent (void)
657 {
658 char *env = getenv ("RC_EINDENT");
659 int amount = 0;
660 char num[10];
661
662 if (env) {
663 errno = 0;
664 amount = strtol (env, NULL, 0);
665 if (errno != 0)
666 amount = 0;
667 }
668
669 amount += INDENT_WIDTH;
670 if (amount > INDENT_MAX)
671 amount = INDENT_MAX;
672
673 snprintf (num, 10, "%08d", amount);
674 setenv ("RC_EINDENT", num, 1);
675 }
676 hidden_def(eindent)
677
678 void eoutdent (void)
679 {
680 char *env = getenv ("RC_EINDENT");
681 int amount = 0;
682 char num[10];
683
684 if (! env)
685 return;
686
687 errno = 0;
688 amount = strtol (env, NULL, 0);
689 if (errno != 0)
690 amount = 0;
691 else
692 amount -= INDENT_WIDTH;
693
694 if (amount <= 0)
695 unsetenv ("RC_EINDENT");
696 else {
697 snprintf (num, 10, "%08d", amount);
698 setenv ("RC_EINDENT", num, 1);
699 }
700 }
701 hidden_def(eoutdent)
702
703 int einfovn (const char *fmt, ...)
704 {
705 int retval;
706 va_list ap;
707
708 CHECK_VERBOSE;
709
710 if (! fmt)
711 return (0);
712
713 va_start (ap, fmt);
714 retval = _einfovn (fmt, ap);
715 va_end (ap);
716
717 return (retval);
718 }
719 hidden_def(einfovn)
720
721 int ewarnvn (const char *fmt, ...)
722 {
723 int retval;
724 va_list ap;
725
726 CHECK_VERBOSE;
727
728 if (! fmt)
729 return (0);
730
731 va_start (ap, fmt);
732 retval = _ewarnvn (fmt, ap);
733 va_end (ap);
734
735 return (retval);
736 }
737 hidden_def(ewarnvn)
738
739 int einfov (const char *fmt, ...)
740 {
741 int retval;
742 va_list ap;
743
744 CHECK_VERBOSE;
745
746 if (! fmt)
747 return (0);
748
749 va_start (ap, fmt);
750 retval = _einfovn (fmt, ap);
751 retval += printf ("\n");
752 va_end (ap);
753
754 return (retval);
755 }
756 hidden_def(einfov)
757
758 int ewarnv (const char *fmt, ...)
759 {
760 int retval;
761 va_list ap;
762
763 CHECK_VERBOSE;
764
765 if (! fmt)
766 return (0);
767
768 va_start (ap, fmt);
769 retval = _ewarnvn (fmt, ap);
770 retval += printf ("\n");
771 va_end (ap);
772
773 return (retval);
774 }
775 hidden_def(ewarnv)
776
777 int ebeginv (const char *fmt, ...)
778 {
779 int retval;
780 va_list ap;
781
782 CHECK_VERBOSE;
783
784 if (! fmt)
785 return (0);
786
787 va_start (ap, fmt);
788 retval = _einfovn (fmt, ap);
789 retval += printf (" ...");
790 if (colour_terminal ())
791 retval += printf ("\n");
792 va_end (ap);
793
794 return (retval);
795 }
796 hidden_def(ebeginv)
797
798 int eendv (int retval, const char *fmt, ...)
799 {
800 va_list ap;
801
802 CHECK_VERBOSE;
803
804 va_start (ap, fmt);
805 _do_eend ("eendv", retval, fmt, ap);
806 va_end (ap);
807
808 return (retval);
809 }
810 hidden_def(eendv)
811
812 int ewendv (int retval, const char *fmt, ...)
813 {
814 va_list ap;
815
816 CHECK_VERBOSE;
817
818 va_start (ap, fmt);
819 _do_eend ("ewendv", retval, fmt, ap);
820 va_end (ap);
821
822 return (retval);
823 }
824 hidden_def(ewendv)
825
826 void eindentv (void)
827 {
828 if (is_env ("RC_VERBOSE", "yes"))
829 eindent ();
830 }
831 hidden_def(eindentv)
832
833 void eoutdentv (void)
834 {
835 if (is_env ("RC_VERBOSE", "yes"))
836 eoutdent ();
837 }
838 hidden_def(eoutdentv)

  ViewVC Help
Powered by ViewVC 1.1.20