Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/runit/svlogd.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 28  ADVISED OF THE POSSIBILITY OF SUCH DAMAG Line 28  ADVISED OF THE POSSIBILITY OF SUCH DAMAG
28  /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */  /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29  /* TODO: depends on runit_lib.c - review and reduce/eliminate */  /* TODO: depends on runit_lib.c - review and reduce/eliminate */
30    
31    /*
32    Config files
33    
34    On startup, and after receiving a HUP signal, svlogd checks for each
35    log directory log if the configuration file log/config exists,
36    and if so, reads the file line by line and adjusts configuration
37    for log as follows:
38    
39    If the line is empty, or starts with a #, it is ignored. A line
40    of the form
41    
42    ssize
43        sets the maximum file size of current when svlogd should rotate
44        the current log file to size bytes. Default is 1000000.
45        If size is zero, svlogd doesnt rotate log files
46        You should set size to at least (2 * len).
47    nnum
48        sets the number of old log files svlogd should maintain to num.
49        If svlogd sees more that num old log files in log after log file
50        rotation, it deletes the oldest one. Default is 10.
51        If num is zero, svlogd doesnt remove old log files.
52    Nmin
53        sets the minimum number of old log files svlogd should maintain
54        to min. min must be less than num. If min is set, and svlogd
55        cannot write to current because the filesystem is full,
56        and it sees more than min old log files, it deletes the oldest one.
57    ttimeout
58        sets the maximum age of the current log file when svlogd should
59        rotate the current log file to timeout seconds. If current
60        is timeout seconds old, and is not empty, svlogd forces log file rotation.
61    !processor
62        tells svlogd to feed each recent log file through processor
63        (see above) on log file rotation. By default log files are not processed.
64    ua.b.c.d[:port]
65        tells svlogd to transmit the first len characters of selected
66        log messages to the IP address a.b.c.d, port number port.
67        If port isnt set, the default port for syslog is used (514).
68        len can be set through the -l option, see below. If svlogd
69        has trouble sending udp packets, it writes error messages
70        to the log directory. Attention: logging through udp is unreliable,
71        and should be used in private networks only.
72    Ua.b.c.d[:port]
73        is the same as the u line above, but the log messages are no longer
74        written to the log directory, but transmitted through udp only.
75        Error messages from svlogd concerning sending udp packages still go
76        to the log directory.
77    pprefix
78        tells svlogd to prefix each line to be written to the log directory,
79        to standard error, or through UDP, with prefix.
80    
81    If a line starts with a -, +, e, or E, svlogd matches the first len characters
82    of each log message against pattern and acts accordingly:
83    
84    -pattern
85        the log message is deselected.
86    +pattern
87        the log message is selected.
88    epattern
89        the log message is selected to be printed to standard error.
90    Epattern
91        the log message is deselected to be printed to standard error.
92    
93    Initially each line is selected to be written to log/current. Deselected
94    log messages are discarded from log. Initially each line is deselected
95    to be written to standard err. Log messages selected for standard error
96    are written to standard error.
97    
98    Pattern Matching
99    
100    svlogd matches a log message against the string pattern as follows:
101    
102    pattern is applied to the log message one character by one, starting
103    with the first. A character not a star (*) and not a plus (+) matches itself.
104    A plus matches the next character in pattern in the log message one
105    or more times. A star before the end of pattern matches any string
106    in the log message that does not include the next character in pattern.
107    A star at the end of pattern matches any string.
108    
109    Timestamps optionally added by svlogd are not considered part
110    of the log message.
111    
112    An svlogd pattern is not a regular expression. For example consider
113    a log message like this
114    
115    2005-12-18_09:13:50.97618 tcpsvd: info: pid 1977 from 10.4.1.14
116    
117    The following pattern doesnt match
118    
119    -*pid*
120    
121    because the first star matches up to the first p in tcpsvd,
122    and then the match fails because i is not s. To match this
123    log message, you can use a pattern like this instead
124    
125    -*: *: pid *
126    */
127    
128  #include <sys/poll.h>  #include <sys/poll.h>
129  #include <sys/file.h>  #include <sys/file.h>
130  #include "libbb.h"  #include "libbb.h"
# Line 72  struct globals { Line 169  struct globals {
169   int wstat;   int wstat;
170   unsigned nearest_rotate;   unsigned nearest_rotate;
171    
172     void* (*memRchr)(const void *, int, size_t);
173    
174   smallint exitasap;   smallint exitasap;
175   smallint rotateasap;   smallint rotateasap;
176   smallint reopenasap;   smallint reopenasap;
# Line 94  struct globals { Line 193  struct globals {
193  #define fndir          (G.fndir         )  #define fndir          (G.fndir         )
194  #define fdwdir         (G.fdwdir        )  #define fdwdir         (G.fdwdir        )
195  #define wstat          (G.wstat         )  #define wstat          (G.wstat         )
196    #define memRchr        (G.memRchr       )
197  #define nearest_rotate (G.nearest_rotate)  #define nearest_rotate (G.nearest_rotate)
198  #define exitasap       (G.exitasap      )  #define exitasap       (G.exitasap      )
199  #define rotateasap     (G.rotateasap    )  #define rotateasap     (G.rotateasap    )
# Line 121  struct globals { Line 221  struct globals {
221  #define PAUSE "pausing: "  #define PAUSE "pausing: "
222  #define INFO "info: "  #define INFO "info: "
223    
 #define usage() bb_show_usage()  
224  static void fatalx(const char *m0)  static void fatalx(const char *m0)
225  {  {
226   bb_error_msg_and_die(FATAL"%s", m0);   bb_error_msg_and_die(FATAL"%s", m0);
# Line 167  static char* wstrdup(const char *str) Line 266  static char* wstrdup(const char *str)
266  /* NUL terminated */  /* NUL terminated */
267  static void fmt_time_human_30nul(char *s)  static void fmt_time_human_30nul(char *s)
268  {  {
269   struct tm *t;   struct tm *ptm;
270   struct timeval tv;   struct timeval tv;
271    
272   gettimeofday(&tv, NULL);   gettimeofday(&tv, NULL);
273   t = gmtime(&(tv.tv_sec));   ptm = gmtime(&tv.tv_sec);
274   sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",   sprintf(s, "%04u-%02u-%02u_%02u:%02u:%02u.%06u000",
275   (unsigned)(1900 + t->tm_year),   (unsigned)(1900 + ptm->tm_year),
276   (unsigned)(t->tm_mon + 1),   (unsigned)(ptm->tm_mon + 1),
277   (unsigned)(t->tm_mday),   (unsigned)(ptm->tm_mday),
278   (unsigned)(t->tm_hour),   (unsigned)(ptm->tm_hour),
279   (unsigned)(t->tm_min),   (unsigned)(ptm->tm_min),
280   (unsigned)(t->tm_sec),   (unsigned)(ptm->tm_sec),
281   (unsigned)(tv.tv_usec)   (unsigned)(tv.tv_usec)
282   );   );
283   /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */   /* 4+1 + 2+1 + 2+1 + 2+1 + 2+1 + 2+1 + 9 = */
# Line 223  static void processorstart(struct logdir Line 322  static void processorstart(struct logdir
322   while ((pid = vfork()) == -1)   while ((pid = vfork()) == -1)
323   pause2cannot("vfork for processor", ld->name);   pause2cannot("vfork for processor", ld->name);
324   if (!pid) {   if (!pid) {
  char *prog[4];  
325   int fd;   int fd;
326    
327   /* child */   /* child */
# Line 256  static void processorstart(struct logdir Line 354  static void processorstart(struct logdir
354   xmove_fd(fd, 5);   xmove_fd(fd, 5);
355    
356  // getenv("SHELL")?  // getenv("SHELL")?
357   prog[0] = (char*)"sh";   execl("/bin/sh", "/bin/sh" + 5, "-c", ld->processor, (char*) NULL);
  prog[1] = (char*)"-c";  
  prog[2] = ld->processor;  
  prog[3] = NULL;  
  execv("/bin/sh", prog);  
358   bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);   bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name);
359   }   }
360   ld->fnsave[26] = sv_ch; /* ...restore */   ld->fnsave[26] = sv_ch; /* ...restore */
# Line 278  static unsigned processorstop(struct log Line 372  static unsigned processorstop(struct log
372   sig_block(SIGHUP);   sig_block(SIGHUP);
373   ld->ppid = 0;   ld->ppid = 0;
374   }   }
375   if (ld->fddir == -1) return 1;   if (ld->fddir == -1)
376     return 1;
377   while (fchdir(ld->fddir) == -1)   while (fchdir(ld->fddir) == -1)
378   pause2cannot("change directory, want processor", ld->name);   pause2cannot("change directory, want processor", ld->name);
379   if (wait_exitcode(wstat) != 0) {   if (WEXITSTATUS(wstat) != 0) {
380   warnx("processor failed, restart", ld->name);   warnx("processor failed, restart", ld->name);
381   ld->fnsave[26] = 't';   ld->fnsave[26] = 't';
382   unlink(ld->fnsave);   unlink(ld->fnsave);
# Line 398  static unsigned rotate(struct logdir *ld Line 493  static unsigned rotate(struct logdir *ld
493   pause2cannot("rename current", ld->name);   pause2cannot("rename current", ld->name);
494   while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)   while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
495   pause2cannot("create new current", ld->name);   pause2cannot("create new current", ld->name);
496   /* we presume this cannot fail */   while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL) ////
497   ld->filecur = fdopen(ld->fdcur, "a"); ////   pause2cannot("create new current", ld->name); /* very unlikely */
498   setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////   setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
499   close_on_exec_on(ld->fdcur);   close_on_exec_on(ld->fdcur);
500   ld->size = 0;   ld->size = 0;
501   while (fchmod(ld->fdcur, 0644) == -1)   while (fchmod(ld->fdcur, 0644) == -1)
502   pause2cannot("set mode of current", ld->name);   pause2cannot("set mode of current", ld->name);
503    
504   rmoldest(ld);   rmoldest(ld);
505   processorstart(ld);   processorstart(ld);
506   }   }
# Line 507  static void logdir_close(struct logdir * Line 603  static void logdir_close(struct logdir *
603   ld->processor = NULL;   ld->processor = NULL;
604  }  }
605    
606  static unsigned logdir_open(struct logdir *ld, const char *fn)  static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn)
607  {  {
608   char buf[128];   char buf[128];
609   unsigned now;   unsigned now;
# Line 551  static unsigned logdir_open(struct logdi Line 647  static unsigned logdir_open(struct logdi
647   free(ld->processor); ld->processor = NULL;   free(ld->processor); ld->processor = NULL;
648    
649   /* read config */   /* read config */
650   i = open_read_close("config", buf, sizeof(buf));   i = open_read_close("config", buf, sizeof(buf) - 1);
651   if (i < 0 && errno != ENOENT)   if (i < 0 && errno != ENOENT)
652   bb_perror_msg(WARNING"%s/config", ld->name);   bb_perror_msg(WARNING"%s/config", ld->name);
653   if (i > 0) {   if (i > 0) {
654     buf[i] = '\0';
655   if (verbose)   if (verbose)
656   bb_error_msg(INFO"read: %s/config", ld->name);   bb_error_msg(INFO"read: %s/config", ld->name);
657   s = buf;   s = buf;
# Line 567  static unsigned logdir_open(struct logdi Line 664  static unsigned logdir_open(struct logdi
664   case '-':   case '-':
665   case 'e':   case 'e':
666   case 'E':   case 'E':
667     /* Filtering requires one-line buffering,
668     * resetting the "find newline" function
669     * accordingly */
670     memRchr = memchr;
671   /* Add '\n'-terminated line to ld->inst */   /* Add '\n'-terminated line to ld->inst */
672   while (1) {   while (1) {
673   int l = asprintf(&new, "%s%s\n", ld->inst ? : "", s);   int l = asprintf(&new, "%s%s\n", ld->inst ? ld->inst : "", s);
674   if (l >= 0 && new)   if (l >= 0 && new)
675   break;   break;
676   pause_nomem();   pause_nomem();
# Line 581  static unsigned logdir_open(struct logdi Line 682  static unsigned logdir_open(struct logdi
682   static const struct suffix_mult km_suffixes[] = {   static const struct suffix_mult km_suffixes[] = {
683   { "k", 1024 },   { "k", 1024 },
684   { "m", 1024*1024 },   { "m", 1024*1024 },
685   { }   { "", 0 }
686   };   };
687   ld->sizemax = xatou_sfx(&s[1], km_suffixes);   ld->sizemax = xatou_sfx(&s[1], km_suffixes);
688   break;   break;
# Line 597  static unsigned logdir_open(struct logdi Line 698  static unsigned logdir_open(struct logdi
698   { "m", 60 },   { "m", 60 },
699   { "h", 60*60 },   { "h", 60*60 },
700   /*{ "d", 24*60*60 },*/   /*{ "d", 24*60*60 },*/
701   { }   { "", 0 }
702   };   };
703   ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);   ld->rotate_period = xatou_sfx(&s[1], mh_suffixes);
704   if (ld->rotate_period) {   if (ld->rotate_period) {
# Line 660  static unsigned logdir_open(struct logdi Line 761  static unsigned logdir_open(struct logdi
761   }   }
762   while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)   while ((ld->fdcur = open("current", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600)) == -1)
763   pause2cannot("open current", ld->name);   pause2cannot("open current", ld->name);
764   /* we presume this cannot fail */   while ((ld->filecur = fdopen(ld->fdcur, "a")) == NULL)
765   ld->filecur = fdopen(ld->fdcur, "a"); ////   pause2cannot("open current", ld->name); ////
766   setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////   setvbuf(ld->filecur, NULL, _IOFBF, linelen); ////
767    
768   close_on_exec_on(ld->fdcur);   close_on_exec_on(ld->fdcur);
# Line 711  static int buffer_pread(/*int fd, */char Line 812  static int buffer_pread(/*int fd, */char
812   struct pollfd input;   struct pollfd input;
813   int i;   int i;
814    
815   input.fd = 0;   input.fd = STDIN_FILENO;
816   input.events = POLLIN;   input.events = POLLIN;
817    
818   do {   do {
# Line 855  static void logmatch(struct logdir *ld) Line 956  static void logmatch(struct logdir *ld)
956  int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;  int svlogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
957  int svlogd_main(int argc, char **argv)  int svlogd_main(int argc, char **argv)
958  {  {
959   char *r,*l,*b;   char *r, *l, *b;
960   ssize_t stdin_cnt = 0;   ssize_t stdin_cnt = 0;
961   int i;   int i;
962   unsigned opt;   unsigned opt;
963   unsigned timestamp = 0;   unsigned timestamp = 0;
  void* (*memRchr)(const void *, int, size_t) = memchr;  
964    
965   INIT_G();   INIT_G();
966    
# Line 869  int svlogd_main(int argc, char **argv) Line 969  int svlogd_main(int argc, char **argv)
969   &r, &replace, &l, &b, &timestamp, &verbose);   &r, &replace, &l, &b, &timestamp, &verbose);
970   if (opt & 1) { // -r   if (opt & 1) { // -r
971   repl = r[0];   repl = r[0];
972   if (!repl || r[1]) usage();   if (!repl || r[1])
973     bb_show_usage();
974   }   }
975   if (opt & 2) if (!repl) repl = '_'; // -R   if (opt & 2) if (!repl) repl = '_'; // -R
976   if (opt & 4) { // -l   if (opt & 4) { // -l
977   linemax = xatou_range(l, 0, BUFSIZ-26);   linemax = xatou_range(l, 0, BUFSIZ-26);
978   if (linemax == 0) linemax = BUFSIZ-26;   if (linemax == 0)
979   if (linemax < 256) linemax = 256;   linemax = BUFSIZ-26;
980     if (linemax < 256)
981     linemax = 256;
982   }   }
983   ////if (opt & 8) { // -b   ////if (opt & 8) { // -b
984   //// buflen = xatoi_u(b);   //// buflen = xatoi_u(b);
# Line 888  int svlogd_main(int argc, char **argv) Line 991  int svlogd_main(int argc, char **argv)
991   argc -= optind;   argc -= optind;
992    
993   dirn = argc;   dirn = argc;
994   if (dirn <= 0) usage();   if (dirn <= 0)
995   ////if (buflen <= linemax) usage();   bb_show_usage();
996     ////if (buflen <= linemax) bb_show_usage();
997   fdwdir = xopen(".", O_RDONLY|O_NDELAY);   fdwdir = xopen(".", O_RDONLY|O_NDELAY);
998   close_on_exec_on(fdwdir);   close_on_exec_on(fdwdir);
999   dir = xzalloc(dirn * sizeof(struct logdir));   dir = xzalloc(dirn * sizeof(dir[0]));
1000   for (i = 0; i < dirn; ++i) {   for (i = 0; i < dirn; ++i) {
1001   dir[i].fddir = -1;   dir[i].fddir = -1;
1002   dir[i].fdcur = -1;   dir[i].fdcur = -1;
# Line 912  int svlogd_main(int argc, char **argv) Line 1016  int svlogd_main(int argc, char **argv)
1016   sigaddset(&blocked_sigset, SIGALRM);   sigaddset(&blocked_sigset, SIGALRM);
1017   sigaddset(&blocked_sigset, SIGHUP);   sigaddset(&blocked_sigset, SIGHUP);
1018   sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);   sigprocmask(SIG_BLOCK, &blocked_sigset, NULL);
1019   bb_signals_recursive(1 << SIGTERM, sig_term_handler);   bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler);
1020   bb_signals_recursive(1 << SIGCHLD, sig_child_handler);   bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler);
1021   bb_signals_recursive(1 << SIGALRM, sig_alarm_handler);   bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler);
1022   bb_signals_recursive(1 << SIGHUP, sig_hangup_handler);   bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler);
   
  logdirs_reopen();  
1023    
1024   /* Without timestamps, we don't have to print each line   /* Without timestamps, we don't have to print each line
1025   * separately, so we can look for _last_ newline, not first,   * separately, so we can look for _last_ newline, not first,
1026   * thus batching writes */   * thus batching writes. If filtering is enabled in config,
1027   if (!timestamp)   * logdirs_reopen resets it to memchr.
1028   memRchr = memrchr;   */
1029     memRchr = (timestamp ? memchr : memrchr);
1030    
1031     logdirs_reopen();
1032    
1033   setvbuf(stderr, NULL, _IOFBF, linelen);   setvbuf(stderr, NULL, _IOFBF, linelen);
1034    
# Line 991  int svlogd_main(int argc, char **argv) Line 1096  int svlogd_main(int argc, char **argv)
1096   }   }
1097   for (i = 0; i < dirn; ++i) {   for (i = 0; i < dirn; ++i) {
1098   struct logdir *ld = &dir[i];   struct logdir *ld = &dir[i];
1099   if (ld->fddir == -1) continue;   if (ld->fddir == -1)
1100     continue;
1101   if (ld->inst)   if (ld->inst)
1102   logmatch(ld);   logmatch(ld);
1103   if (ld->matcherr == 'e') {   if (ld->matcherr == 'e') {
# Line 999  int svlogd_main(int argc, char **argv) Line 1105  int svlogd_main(int argc, char **argv)
1105   ////full_write(STDERR_FILENO, printptr, printlen);   ////full_write(STDERR_FILENO, printptr, printlen);
1106   fwrite(printptr, 1, printlen, stderr);   fwrite(printptr, 1, printlen, stderr);
1107   }   }
1108   if (ld->match != '+') continue;   if (ld->match != '+')
1109     continue;
1110   buffer_pwrite(i, printptr, printlen);   buffer_pwrite(i, printptr, printlen);
1111   }   }
1112    
# Line 1022  int svlogd_main(int argc, char **argv) Line 1129  int svlogd_main(int argc, char **argv)
1129   }   }
1130   /* linelen == no of chars incl. '\n' (or == stdin_cnt) */   /* linelen == no of chars incl. '\n' (or == stdin_cnt) */
1131   for (i = 0; i < dirn; ++i) {   for (i = 0; i < dirn; ++i) {
1132   if (dir[i].fddir == -1) continue;   if (dir[i].fddir == -1)
1133     continue;
1134   if (dir[i].matcherr == 'e') {   if (dir[i].matcherr == 'e') {
1135   ////full_write(STDERR_FILENO, lineptr, linelen);   ////full_write(STDERR_FILENO, lineptr, linelen);
1136   fwrite(lineptr, 1, linelen, stderr);   fwrite(lineptr, 1, linelen, stderr);
1137   }   }
1138   if (dir[i].match != '+') continue;   if (dir[i].match != '+')
1139     continue;
1140   buffer_pwrite(i, lineptr, linelen);   buffer_pwrite(i, lineptr, linelen);
1141   }   }
1142   }   }
# Line 1043  int svlogd_main(int argc, char **argv) Line 1152  int svlogd_main(int argc, char **argv)
1152   /* Move unprocessed data to the front of line */   /* Move unprocessed data to the front of line */
1153   memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);   memmove((timestamp ? line+26 : line), lineptr, stdin_cnt);
1154   }   }
1155   fflush(NULL);////   fflush_all();////
1156   }   }
1157    
1158   for (i = 0; i < dirn; ++i) {   for (i = 0; i < dirn; ++i) {
1159   if (dir[i].ppid)   if (dir[i].ppid)
1160   while (!processorstop(&dir[i]))   while (!processorstop(&dir[i]))
1161   /* repeat */;   continue;
1162   logdir_close(&dir[i]);   logdir_close(&dir[i]);
1163   }   }
1164   return 0;   return 0;

Legend:
Removed from v.983  
changed lines
  Added in v.984