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

Contents of /trunk/src/libeinfo.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.20