diff options
author | nobody <nobody@localhost> | 2004-10-13 09:42:10 +0000 |
---|---|---|
committer | nobody <nobody@localhost> | 2004-10-13 09:42:10 +0000 |
commit | 8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373 (patch) | |
tree | 1826706cd4fd009fcd14f4f8021005ec8ec0fa59 /busybox/sysklogd | |
download | busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.tar.gz busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.tar.bz2 busybox-w32-8c59a0bf0e9e2d87b0ff273ea3f0bf05bbbf6373.zip |
This commit was manufactured by cvs2svn to create tag 'busybox_1_00'.
Diffstat (limited to 'busybox/sysklogd')
-rw-r--r-- | busybox/sysklogd/Config.in | 109 | ||||
-rw-r--r-- | busybox/sysklogd/Makefile | 32 | ||||
-rw-r--r-- | busybox/sysklogd/Makefile.in | 39 | ||||
-rw-r--r-- | busybox/sysklogd/klogd.c | 165 | ||||
-rw-r--r-- | busybox/sysklogd/logger.c | 204 | ||||
-rw-r--r-- | busybox/sysklogd/logread.c | 186 | ||||
-rw-r--r-- | busybox/sysklogd/syslogd.c | 712 |
7 files changed, 1447 insertions, 0 deletions
diff --git a/busybox/sysklogd/Config.in b/busybox/sysklogd/Config.in new file mode 100644 index 000000000..f77d79e8c --- /dev/null +++ b/busybox/sysklogd/Config.in | |||
@@ -0,0 +1,109 @@ | |||
1 | # | ||
2 | # For a description of the syntax of this configuration file, | ||
3 | # see scripts/kbuild/config-language.txt. | ||
4 | # | ||
5 | |||
6 | menu "System Logging Utilities" | ||
7 | |||
8 | config CONFIG_SYSLOGD | ||
9 | bool "syslogd" | ||
10 | default n | ||
11 | help | ||
12 | The syslogd utility is used to record logs of all the | ||
13 | significant events that occur on a system. Every | ||
14 | message that is logged records the date and time of the | ||
15 | event, and will generally also record the name of the | ||
16 | application that generated the message. When used in | ||
17 | conjunction with klogd, messages from the Linux kernel | ||
18 | can also be recorded. This is terribly useful, | ||
19 | especially for finding what happened when something goes | ||
20 | wrong. And something almost always will go wrong if | ||
21 | you wait long enough.... | ||
22 | |||
23 | config CONFIG_FEATURE_ROTATE_LOGFILE | ||
24 | bool " Rotate message files" | ||
25 | default n | ||
26 | depends on CONFIG_SYSLOGD | ||
27 | help | ||
28 | This enables syslogd to rotate the message files | ||
29 | on his own. No need to use an external rotatescript. | ||
30 | |||
31 | config CONFIG_FEATURE_REMOTE_LOG | ||
32 | bool " Remote Log support" | ||
33 | default n | ||
34 | depends on CONFIG_SYSLOGD | ||
35 | help | ||
36 | When you enable this feature, the syslogd utility can | ||
37 | be used to send system log messages to another system | ||
38 | connected via a network. This allows the remote | ||
39 | machine to log all the system messages, which can be | ||
40 | terribly useful for reducing the number of serial | ||
41 | cables you use. It can also be a very good security | ||
42 | measure to prevent system logs from being tampered with | ||
43 | by an intruder. | ||
44 | |||
45 | config CONFIG_FEATURE_IPC_SYSLOG | ||
46 | bool " Circular Buffer support" | ||
47 | default n | ||
48 | depends on CONFIG_SYSLOGD | ||
49 | help | ||
50 | When you enable this feature, the syslogd utility will | ||
51 | use a circular buffer to record system log messages. | ||
52 | When the buffer is filled it will continue to overwrite | ||
53 | the oldest messages. This can be very useful for | ||
54 | systems with little or no permanent storage, since | ||
55 | otherwise system logs can eventually fill up your | ||
56 | entire filesystem, which may cause your system to | ||
57 | break badly. | ||
58 | |||
59 | config CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE | ||
60 | int " Circular buffer size in Kbytes (minimum 4KB)" | ||
61 | default 16 | ||
62 | depends on CONFIG_FEATURE_IPC_SYSLOG | ||
63 | help | ||
64 | This option sets the size of the circular buffer | ||
65 | used to record system log messages. | ||
66 | |||
67 | config CONFIG_LOGREAD | ||
68 | bool " logread" | ||
69 | default y | ||
70 | depends on CONFIG_FEATURE_IPC_SYSLOG | ||
71 | help | ||
72 | If you enabled Circular Buffer support, you almost | ||
73 | certainly want to enable this feature as well. This | ||
74 | utility will allow you to read the messages that are | ||
75 | stored in the syslogd circular buffer. | ||
76 | |||
77 | config CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING | ||
78 | bool " logread double buffering" | ||
79 | default n | ||
80 | depends on CONFIG_LOGREAD | ||
81 | help | ||
82 | 'logread' ouput to slow serial terminals can have | ||
83 | side effects on syslog because of the semaphore. | ||
84 | This option make logread to double buffer copy | ||
85 | from circular buffer, minimizing semaphore | ||
86 | contention at some minor memory expense. | ||
87 | |||
88 | config CONFIG_KLOGD | ||
89 | bool "klogd" | ||
90 | default n | ||
91 | depends on CONFIG_SYSLOGD | ||
92 | help | ||
93 | klogd is a utility which intercepts and logs all | ||
94 | messages from the Linux kernel and sends the messages | ||
95 | out to the 'syslogd' utility so they can be logged. If | ||
96 | you wish to record the messages produced by the kernel, | ||
97 | you should enable this option. | ||
98 | |||
99 | config CONFIG_LOGGER | ||
100 | bool "logger" | ||
101 | default n | ||
102 | help | ||
103 | The logger utility allows you to send arbitrary text | ||
104 | messages to the system log (i.e. the 'syslogd' utility) so | ||
105 | they can be logged. This is generally used to help locate | ||
106 | problems that occur within programs and scripts. | ||
107 | |||
108 | endmenu | ||
109 | |||
diff --git a/busybox/sysklogd/Makefile b/busybox/sysklogd/Makefile new file mode 100644 index 000000000..78b0c0090 --- /dev/null +++ b/busybox/sysklogd/Makefile | |||
@@ -0,0 +1,32 @@ | |||
1 | # Makefile for busybox | ||
2 | # | ||
3 | # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | # | ||
19 | |||
20 | top_srcdir=.. | ||
21 | top_buildddir=.. | ||
22 | srcdir=$(top_srcdir)/sysklogd | ||
23 | SYSKLOGD_DIR:=./ | ||
24 | include $(top_builddir)/Rules.mak | ||
25 | include $(top_builddir)/.config | ||
26 | include Makefile.in | ||
27 | all: $(libraries-y) | ||
28 | -include $(top_builddir)/.depend | ||
29 | |||
30 | clean: | ||
31 | rm -f *.o *.a $(AR_TARGET) | ||
32 | |||
diff --git a/busybox/sysklogd/Makefile.in b/busybox/sysklogd/Makefile.in new file mode 100644 index 000000000..99a5f823c --- /dev/null +++ b/busybox/sysklogd/Makefile.in | |||
@@ -0,0 +1,39 @@ | |||
1 | # Makefile for busybox | ||
2 | # | ||
3 | # Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | # General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, write to the Free Software | ||
17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | # | ||
19 | |||
20 | SYSKLOGD_AR:=sysklogd.a | ||
21 | ifndef $(SYSKLOGD_DIR) | ||
22 | SYSKLOGD_DIR:=$(top_builddir)/sysklogd/ | ||
23 | endif | ||
24 | srcdir=$(top_srcdir)/sysklogd | ||
25 | |||
26 | SYSKLOGD-:= | ||
27 | SYSKLOGD-$(CONFIG_KLOGD) += klogd.o | ||
28 | SYSKLOGD-$(CONFIG_LOGGER) += logger.o | ||
29 | SYSKLOGD-$(CONFIG_LOGREAD) += logread.o | ||
30 | SYSKLOGD-$(CONFIG_SYSLOGD) += syslogd.o | ||
31 | |||
32 | libraries-y+=$(SYSKLOGD_DIR)$(SYSKLOGD_AR) | ||
33 | |||
34 | $(SYSKLOGD_DIR)$(SYSKLOGD_AR): $(patsubst %,$(SYSKLOGD_DIR)%, $(SYSKLOGD-y)) | ||
35 | $(AR) -ro $@ $(patsubst %,$(SYSKLOGD_DIR)%, $(SYSKLOGD-y)) | ||
36 | |||
37 | $(SYSKLOGD_DIR)%.o: $(srcdir)/%.c | ||
38 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< | ||
39 | |||
diff --git a/busybox/sysklogd/klogd.c b/busybox/sysklogd/klogd.c new file mode 100644 index 000000000..c908b593c --- /dev/null +++ b/busybox/sysklogd/klogd.c | |||
@@ -0,0 +1,165 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini klogd implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>. | ||
6 | * Changes: Made this a standalone busybox module which uses standalone | ||
7 | * syslog() client interface. | ||
8 | * | ||
9 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
10 | * | ||
11 | * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org> | ||
12 | * | ||
13 | * "circular buffer" Copyright (C) 2000 by Gennady Feldman <gfeldman@gena01.com> | ||
14 | * | ||
15 | * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001 | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License as published by | ||
19 | * the Free Software Foundation; either version 2 of the License, or | ||
20 | * (at your option) any later version. | ||
21 | * | ||
22 | * This program is distributed in the hope that it will be useful, | ||
23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
25 | * General Public License for more details. | ||
26 | * | ||
27 | * You should have received a copy of the GNU General Public License | ||
28 | * along with this program; if not, write to the Free Software | ||
29 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
30 | * | ||
31 | */ | ||
32 | |||
33 | #include <stdio.h> | ||
34 | #include <stdlib.h> | ||
35 | #include <signal.h> /* for our signal() handlers */ | ||
36 | #include <string.h> /* strncpy() */ | ||
37 | #include <errno.h> /* errno and friends */ | ||
38 | #include <unistd.h> | ||
39 | #include <ctype.h> | ||
40 | #include <sys/syslog.h> | ||
41 | #include <sys/klog.h> | ||
42 | |||
43 | #include "busybox.h" | ||
44 | |||
45 | static void klogd_signal(int sig) | ||
46 | { | ||
47 | klogctl(7, NULL, 0); | ||
48 | klogctl(0, 0, 0); | ||
49 | /* logMessage(0, "Kernel log daemon exiting."); */ | ||
50 | syslog(LOG_NOTICE, "Kernel log daemon exiting."); | ||
51 | exit(EXIT_SUCCESS); | ||
52 | } | ||
53 | |||
54 | static void doKlogd(const int console_log_level) __attribute__ ((noreturn)); | ||
55 | static void doKlogd(const int console_log_level) | ||
56 | { | ||
57 | int priority = LOG_INFO; | ||
58 | char log_buffer[4096]; | ||
59 | int i, n, lastc; | ||
60 | char *start; | ||
61 | |||
62 | openlog("kernel", 0, LOG_KERN); | ||
63 | |||
64 | /* Set up sig handlers */ | ||
65 | signal(SIGINT, klogd_signal); | ||
66 | signal(SIGKILL, klogd_signal); | ||
67 | signal(SIGTERM, klogd_signal); | ||
68 | signal(SIGHUP, SIG_IGN); | ||
69 | |||
70 | /* "Open the log. Currently a NOP." */ | ||
71 | klogctl(1, NULL, 0); | ||
72 | |||
73 | /* Set level of kernel console messaging.. */ | ||
74 | if (console_log_level != -1) | ||
75 | klogctl(8, NULL, console_log_level); | ||
76 | |||
77 | syslog(LOG_NOTICE, "klogd started: " BB_BANNER); | ||
78 | |||
79 | while (1) { | ||
80 | /* Use kernel syscalls */ | ||
81 | memset(log_buffer, '\0', sizeof(log_buffer)); | ||
82 | n = klogctl(2, log_buffer, sizeof(log_buffer)); | ||
83 | if (n < 0) { | ||
84 | if (errno == EINTR) | ||
85 | continue; | ||
86 | syslog(LOG_ERR, "klogd: Error return from sys_sycall: %d - %m.\n", errno); | ||
87 | exit(EXIT_FAILURE); | ||
88 | } | ||
89 | |||
90 | /* klogctl buffer parsing modelled after code in dmesg.c */ | ||
91 | start = &log_buffer[0]; | ||
92 | lastc = '\0'; | ||
93 | for (i = 0; i < n; i++) { | ||
94 | if (lastc == '\0' && log_buffer[i] == '<') { | ||
95 | priority = 0; | ||
96 | i++; | ||
97 | while (isdigit(log_buffer[i])) { | ||
98 | priority = priority * 10 + (log_buffer[i] - '0'); | ||
99 | i++; | ||
100 | } | ||
101 | if (log_buffer[i] == '>') | ||
102 | i++; | ||
103 | start = &log_buffer[i]; | ||
104 | } | ||
105 | if (log_buffer[i] == '\n') { | ||
106 | log_buffer[i] = '\0'; /* zero terminate this message */ | ||
107 | syslog(priority, "%s", start); | ||
108 | start = &log_buffer[i + 1]; | ||
109 | priority = LOG_INFO; | ||
110 | } | ||
111 | lastc = log_buffer[i]; | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | extern int klogd_main(int argc, char **argv) | ||
117 | { | ||
118 | /* no options, no getopt */ | ||
119 | int opt; | ||
120 | int doFork = TRUE; | ||
121 | unsigned char console_log_level = -1; | ||
122 | |||
123 | /* do normal option parsing */ | ||
124 | while ((opt = getopt(argc, argv, "c:n")) > 0) { | ||
125 | switch (opt) { | ||
126 | case 'c': | ||
127 | if ((optarg == NULL) || (optarg[1] != '\0')) { | ||
128 | bb_show_usage(); | ||
129 | } | ||
130 | /* Valid levels are between 1 and 8 */ | ||
131 | console_log_level = *optarg - '1'; | ||
132 | if (console_log_level > 7) { | ||
133 | bb_show_usage(); | ||
134 | } | ||
135 | console_log_level++; | ||
136 | |||
137 | break; | ||
138 | case 'n': | ||
139 | doFork = FALSE; | ||
140 | break; | ||
141 | default: | ||
142 | bb_show_usage(); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | if (doFork) { | ||
147 | #if defined(__uClinux__) | ||
148 | vfork_daemon_rexec(0, 1, argc, argv, "-n"); | ||
149 | #else /* __uClinux__ */ | ||
150 | if (daemon(0, 1) < 0) | ||
151 | bb_perror_msg_and_die("daemon"); | ||
152 | #endif /* __uClinux__ */ | ||
153 | } | ||
154 | doKlogd(console_log_level); | ||
155 | |||
156 | return EXIT_SUCCESS; | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | Local Variables | ||
161 | c-file-style: "linux" | ||
162 | c-basic-offset: 4 | ||
163 | tab-width: 4 | ||
164 | End: | ||
165 | */ | ||
diff --git a/busybox/sysklogd/logger.c b/busybox/sysklogd/logger.c new file mode 100644 index 000000000..16155316f --- /dev/null +++ b/busybox/sysklogd/logger.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini logger implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <stdio.h> | ||
24 | #include <unistd.h> | ||
25 | #include <sys/types.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <ctype.h> | ||
28 | #include <string.h> | ||
29 | #include <stdlib.h> | ||
30 | |||
31 | #include "busybox.h" | ||
32 | #if !defined CONFIG_SYSLOGD | ||
33 | |||
34 | #define SYSLOG_NAMES | ||
35 | #include <sys/syslog.h> | ||
36 | |||
37 | #else | ||
38 | #include <sys/syslog.h> | ||
39 | # ifndef __dietlibc__ | ||
40 | /* We have to do this since the header file defines static | ||
41 | * structures. Argh.... bad libc, bad, bad... | ||
42 | */ | ||
43 | typedef struct _code { | ||
44 | char *c_name; | ||
45 | int c_val; | ||
46 | } CODE; | ||
47 | extern CODE prioritynames[]; | ||
48 | extern CODE facilitynames[]; | ||
49 | # endif | ||
50 | #endif | ||
51 | |||
52 | /* Decode a symbolic name to a numeric value | ||
53 | * this function is based on code | ||
54 | * Copyright (c) 1983, 1993 | ||
55 | * The Regents of the University of California. All rights reserved. | ||
56 | * | ||
57 | * Original copyright notice is retained at the end of this file. | ||
58 | */ | ||
59 | static int decode(char *name, CODE * codetab) | ||
60 | { | ||
61 | CODE *c; | ||
62 | |||
63 | if (isdigit(*name)) | ||
64 | return (atoi(name)); | ||
65 | for (c = codetab; c->c_name; c++) { | ||
66 | if (!strcasecmp(name, c->c_name)) { | ||
67 | return (c->c_val); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | return (-1); | ||
72 | } | ||
73 | |||
74 | /* Decode a symbolic name to a numeric value | ||
75 | * this function is based on code | ||
76 | * Copyright (c) 1983, 1993 | ||
77 | * The Regents of the University of California. All rights reserved. | ||
78 | * | ||
79 | * Original copyright notice is retained at the end of this file. | ||
80 | */ | ||
81 | static int pencode(char *s) | ||
82 | { | ||
83 | char *save; | ||
84 | int lev, fac = LOG_USER; | ||
85 | |||
86 | for (save = s; *s && *s != '.'; ++s); | ||
87 | if (*s) { | ||
88 | *s = '\0'; | ||
89 | fac = decode(save, facilitynames); | ||
90 | if (fac < 0) | ||
91 | bb_error_msg_and_die("unknown facility name: %s", save); | ||
92 | *s++ = '.'; | ||
93 | } else { | ||
94 | s = save; | ||
95 | } | ||
96 | lev = decode(s, prioritynames); | ||
97 | if (lev < 0) | ||
98 | bb_error_msg_and_die("unknown priority name: %s", save); | ||
99 | return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); | ||
100 | } | ||
101 | |||
102 | |||
103 | extern int logger_main(int argc, char **argv) | ||
104 | { | ||
105 | int pri = LOG_USER | LOG_NOTICE; | ||
106 | int option = 0; | ||
107 | int c, i, opt; | ||
108 | char buf[1024], name[128]; | ||
109 | |||
110 | /* Fill out the name string early (may be overwritten later) */ | ||
111 | my_getpwuid(name, geteuid(), sizeof(name)); | ||
112 | |||
113 | /* Parse any options */ | ||
114 | while ((opt = getopt(argc, argv, "p:st:")) > 0) { | ||
115 | switch (opt) { | ||
116 | case 's': | ||
117 | option |= LOG_PERROR; | ||
118 | break; | ||
119 | case 'p': | ||
120 | pri = pencode(optarg); | ||
121 | break; | ||
122 | case 't': | ||
123 | safe_strncpy(name, optarg, sizeof(name)); | ||
124 | break; | ||
125 | default: | ||
126 | bb_show_usage(); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | openlog(name, option, (pri | LOG_FACMASK)); | ||
131 | if (optind == argc) { | ||
132 | do { | ||
133 | /* read from stdin */ | ||
134 | i = 0; | ||
135 | while ((c = getc(stdin)) != EOF && c != '\n' && | ||
136 | i < (sizeof(buf)-1)) { | ||
137 | buf[i++] = c; | ||
138 | } | ||
139 | if (i > 0) { | ||
140 | buf[i++] = '\0'; | ||
141 | syslog(pri, "%s", buf); | ||
142 | } | ||
143 | } while (c != EOF); | ||
144 | } else { | ||
145 | char *message = NULL; | ||
146 | int len = argc - optind; /* for the space between the args | ||
147 | and '\0' */ | ||
148 | opt = len; | ||
149 | argv += optind; | ||
150 | for (i = 0; i < opt; i++) { | ||
151 | len += strlen(*argv); | ||
152 | message = xrealloc(message, len); | ||
153 | if(!i) | ||
154 | message[0] = 0; | ||
155 | else | ||
156 | strcat(message, " "); | ||
157 | strcat(message, *argv); | ||
158 | argv++; | ||
159 | } | ||
160 | syslog(pri, "%s", message); | ||
161 | } | ||
162 | |||
163 | closelog(); | ||
164 | return EXIT_SUCCESS; | ||
165 | } | ||
166 | |||
167 | |||
168 | /*- | ||
169 | * Copyright (c) 1983, 1993 | ||
170 | * The Regents of the University of California. All rights reserved. | ||
171 | * | ||
172 | * This is the original license statement for the decode and pencode functions. | ||
173 | * | ||
174 | * Redistribution and use in source and binary forms, with or without | ||
175 | * modification, are permitted provided that the following conditions | ||
176 | * are met: | ||
177 | * 1. Redistributions of source code must retain the above copyright | ||
178 | * notice, this list of conditions and the following disclaimer. | ||
179 | * 2. Redistributions in binary form must reproduce the above copyright | ||
180 | * notice, this list of conditions and the following disclaimer in the | ||
181 | * documentation and/or other materials provided with the distribution. | ||
182 | * | ||
183 | * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change | ||
184 | * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change> | ||
185 | * | ||
186 | * 4. Neither the name of the University nor the names of its contributors | ||
187 | * may be used to endorse or promote products derived from this software | ||
188 | * without specific prior written permission. | ||
189 | * | ||
190 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||
191 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
192 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
193 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
194 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
195 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
196 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
197 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
198 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
199 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
200 | * SUCH DAMAGE. | ||
201 | */ | ||
202 | |||
203 | |||
204 | |||
diff --git a/busybox/sysklogd/logread.c b/busybox/sysklogd/logread.c new file mode 100644 index 000000000..70d1db631 --- /dev/null +++ b/busybox/sysklogd/logread.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * circular buffer syslog implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 2000 by Gennady Feldman <gfeldman@gena01.com> | ||
6 | * | ||
7 | * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001 | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
22 | * 02111-1307 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | |||
27 | #include <stdio.h> | ||
28 | #include <stdlib.h> | ||
29 | #include <string.h> | ||
30 | #include <sys/ipc.h> | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/sem.h> | ||
33 | #include <sys/shm.h> | ||
34 | #include <signal.h> | ||
35 | #include <setjmp.h> | ||
36 | #include <unistd.h> | ||
37 | #include "busybox.h" | ||
38 | |||
39 | static const long KEY_ID = 0x414e4547; /*"GENA"*/ | ||
40 | |||
41 | static struct shbuf_ds { | ||
42 | int size; // size of data written | ||
43 | int head; // start of message list | ||
44 | int tail; // end of message list | ||
45 | char data[1]; // data/messages | ||
46 | } *buf = NULL; // shared memory pointer | ||
47 | |||
48 | |||
49 | // Semaphore operation structures | ||
50 | static struct sembuf SMrup[1] = {{0, -1, IPC_NOWAIT | SEM_UNDO}}; // set SMrup | ||
51 | static struct sembuf SMrdn[2] = {{1, 0}, {0, +1, SEM_UNDO}}; // set SMrdn | ||
52 | |||
53 | static int log_shmid = -1; // ipc shared memory id | ||
54 | static int log_semid = -1; // ipc semaphore id | ||
55 | static jmp_buf jmp_env; | ||
56 | |||
57 | static void error_exit(const char *str); | ||
58 | static void interrupted(int sig); | ||
59 | |||
60 | /* | ||
61 | * sem_up - up()'s a semaphore. | ||
62 | */ | ||
63 | static inline void sem_up(int semid) | ||
64 | { | ||
65 | if ( semop(semid, SMrup, 1) == -1 ) | ||
66 | error_exit("semop[SMrup]"); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * sem_down - down()'s a semaphore | ||
71 | */ | ||
72 | static inline void sem_down(int semid) | ||
73 | { | ||
74 | if ( semop(semid, SMrdn, 2) == -1 ) | ||
75 | error_exit("semop[SMrdn]"); | ||
76 | } | ||
77 | |||
78 | extern int logread_main(int argc, char **argv) | ||
79 | { | ||
80 | int i; | ||
81 | int follow=0; | ||
82 | |||
83 | if (argc == 2 && strcmp(argv[1],"-f")==0) { | ||
84 | follow = 1; | ||
85 | } else { | ||
86 | /* no options, no getopt */ | ||
87 | if (argc > 1) | ||
88 | bb_show_usage(); | ||
89 | } | ||
90 | |||
91 | // handle intrrupt signal | ||
92 | if (setjmp(jmp_env)) goto output_end; | ||
93 | |||
94 | // attempt to redefine ^C signal | ||
95 | signal(SIGINT, interrupted); | ||
96 | |||
97 | if ( (log_shmid = shmget(KEY_ID, 0, 0)) == -1) | ||
98 | error_exit("Can't find circular buffer"); | ||
99 | |||
100 | // Attach shared memory to our char* | ||
101 | if ( (buf = shmat(log_shmid, NULL, SHM_RDONLY)) == NULL) | ||
102 | error_exit("Can't get access to circular buffer from syslogd"); | ||
103 | |||
104 | if ( (log_semid = semget(KEY_ID, 0, 0)) == -1) | ||
105 | error_exit("Can't get access to semaphone(s) for circular buffer from syslogd"); | ||
106 | |||
107 | // Suppose atomic memory move | ||
108 | i = follow ? buf->tail : buf->head; | ||
109 | |||
110 | do { | ||
111 | #ifdef CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING | ||
112 | char *buf_data; | ||
113 | int log_len,j; | ||
114 | #endif | ||
115 | |||
116 | sem_down(log_semid); | ||
117 | |||
118 | //printf("head: %i tail: %i size: %i\n",buf->head,buf->tail,buf->size); | ||
119 | if (buf->head == buf->tail || i==buf->tail) { | ||
120 | if (follow) { | ||
121 | sem_up(log_semid); | ||
122 | sleep(1); /* TODO: replace me with a sleep_on */ | ||
123 | continue; | ||
124 | } else { | ||
125 | printf("<empty syslog>\n"); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | // Read Memory | ||
130 | #ifdef CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING | ||
131 | log_len = buf->tail - i; | ||
132 | if (log_len < 0) | ||
133 | log_len += buf->size; | ||
134 | buf_data = (char *)malloc(log_len); | ||
135 | if (!buf_data) | ||
136 | error_exit("malloc failed"); | ||
137 | |||
138 | if (buf->tail < i) { | ||
139 | memcpy(buf_data, buf->data+i, buf->size-i); | ||
140 | memcpy(buf_data+buf->size-i, buf->data, buf->tail); | ||
141 | } else { | ||
142 | memcpy(buf_data, buf->data+i, buf->tail-i); | ||
143 | } | ||
144 | i = buf->tail; | ||
145 | |||
146 | #else | ||
147 | while ( i != buf->tail) { | ||
148 | printf("%s", buf->data+i); | ||
149 | i+= strlen(buf->data+i) + 1; | ||
150 | if (i >= buf->size ) | ||
151 | i=0; | ||
152 | } | ||
153 | #endif | ||
154 | // release the lock on the log chain | ||
155 | sem_up(log_semid); | ||
156 | |||
157 | #ifdef CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING | ||
158 | for (j=0; j < log_len; j+=strlen(buf_data+j)+1) { | ||
159 | printf("%s", buf_data+j); | ||
160 | if (follow) | ||
161 | fflush(stdout); | ||
162 | } | ||
163 | free(buf_data); | ||
164 | #endif | ||
165 | } while (follow); | ||
166 | |||
167 | output_end: | ||
168 | if (log_shmid != -1) | ||
169 | shmdt(buf); | ||
170 | |||
171 | return EXIT_SUCCESS; | ||
172 | } | ||
173 | |||
174 | static void interrupted(int sig){ | ||
175 | signal(SIGINT, SIG_IGN); | ||
176 | longjmp(jmp_env, 1); | ||
177 | } | ||
178 | |||
179 | static void error_exit(const char *str){ | ||
180 | perror(str); | ||
181 | //release all acquired resources | ||
182 | if (log_shmid != -1) | ||
183 | shmdt(buf); | ||
184 | |||
185 | exit(1); | ||
186 | } | ||
diff --git a/busybox/sysklogd/syslogd.c b/busybox/sysklogd/syslogd.c new file mode 100644 index 000000000..8c6c44ee0 --- /dev/null +++ b/busybox/sysklogd/syslogd.c | |||
@@ -0,0 +1,712 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Mini syslogd implementation for busybox | ||
4 | * | ||
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> | ||
6 | * | ||
7 | * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org> | ||
8 | * | ||
9 | * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com> | ||
10 | * | ||
11 | * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001 | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <stdio.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <ctype.h> | ||
32 | #include <errno.h> | ||
33 | #include <fcntl.h> | ||
34 | #include <getopt.h> | ||
35 | #include <netdb.h> | ||
36 | #include <paths.h> | ||
37 | #include <signal.h> | ||
38 | #include <stdarg.h> | ||
39 | #include <stdbool.h> | ||
40 | #include <time.h> | ||
41 | #include <string.h> | ||
42 | #include <unistd.h> | ||
43 | #include <sys/socket.h> | ||
44 | #include <sys/types.h> | ||
45 | #include <sys/un.h> | ||
46 | #include <sys/param.h> | ||
47 | |||
48 | #include "busybox.h" | ||
49 | |||
50 | /* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ | ||
51 | #define SYSLOG_NAMES | ||
52 | #include <sys/syslog.h> | ||
53 | #include <sys/uio.h> | ||
54 | |||
55 | /* Path for the file where all log messages are written */ | ||
56 | #define __LOG_FILE "/var/log/messages" | ||
57 | |||
58 | /* Path to the unix socket */ | ||
59 | static char lfile[MAXPATHLEN]; | ||
60 | |||
61 | static const char *logFilePath = __LOG_FILE; | ||
62 | |||
63 | #ifdef CONFIG_FEATURE_ROTATE_LOGFILE | ||
64 | /* max size of message file before being rotated */ | ||
65 | static int logFileSize = 200 * 1024; | ||
66 | |||
67 | /* number of rotated message files */ | ||
68 | static int logFileRotate = 1; | ||
69 | #endif | ||
70 | |||
71 | /* interval between marks in seconds */ | ||
72 | static int MarkInterval = 20 * 60; | ||
73 | |||
74 | /* localhost's name */ | ||
75 | static char LocalHostName[64]; | ||
76 | |||
77 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
78 | #include <netinet/in.h> | ||
79 | /* udp socket for logging to remote host */ | ||
80 | static int remotefd = -1; | ||
81 | static struct sockaddr_in remoteaddr; | ||
82 | |||
83 | /* where do we log? */ | ||
84 | static char *RemoteHost; | ||
85 | |||
86 | /* what port to log to? */ | ||
87 | static int RemotePort = 514; | ||
88 | |||
89 | /* To remote log or not to remote log, that is the question. */ | ||
90 | static int doRemoteLog = FALSE; | ||
91 | static int local_logging = FALSE; | ||
92 | #endif | ||
93 | |||
94 | /* Make loging output smaller. */ | ||
95 | static bool small = false; | ||
96 | |||
97 | |||
98 | #define MAXLINE 1024 /* maximum line length */ | ||
99 | |||
100 | |||
101 | /* circular buffer variables/structures */ | ||
102 | #ifdef CONFIG_FEATURE_IPC_SYSLOG | ||
103 | |||
104 | #if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4 | ||
105 | #error Sorry, you must set the syslogd buffer size to at least 4KB. | ||
106 | #error Please check CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE | ||
107 | #endif | ||
108 | |||
109 | #include <sys/ipc.h> | ||
110 | #include <sys/sem.h> | ||
111 | #include <sys/shm.h> | ||
112 | |||
113 | /* our shared key */ | ||
114 | static const long KEY_ID = 0x414e4547; /*"GENA" */ | ||
115 | |||
116 | // Semaphore operation structures | ||
117 | static struct shbuf_ds { | ||
118 | int size; // size of data written | ||
119 | int head; // start of message list | ||
120 | int tail; // end of message list | ||
121 | char data[1]; // data/messages | ||
122 | } *buf = NULL; // shared memory pointer | ||
123 | |||
124 | static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup | ||
125 | static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn | ||
126 | |||
127 | static int shmid = -1; // ipc shared memory id | ||
128 | static int s_semid = -1; // ipc semaphore id | ||
129 | static int shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024); // default shm size | ||
130 | static int circular_logging = FALSE; | ||
131 | |||
132 | /* | ||
133 | * sem_up - up()'s a semaphore. | ||
134 | */ | ||
135 | static inline void sem_up(int semid) | ||
136 | { | ||
137 | if (semop(semid, SMwup, 1) == -1) { | ||
138 | bb_perror_msg_and_die("semop[SMwup]"); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | * sem_down - down()'s a semaphore | ||
144 | */ | ||
145 | static inline void sem_down(int semid) | ||
146 | { | ||
147 | if (semop(semid, SMwdn, 3) == -1) { | ||
148 | bb_perror_msg_and_die("semop[SMwdn]"); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | |||
153 | void ipcsyslog_cleanup(void) | ||
154 | { | ||
155 | printf("Exiting Syslogd!\n"); | ||
156 | if (shmid != -1) { | ||
157 | shmdt(buf); | ||
158 | } | ||
159 | |||
160 | if (shmid != -1) { | ||
161 | shmctl(shmid, IPC_RMID, NULL); | ||
162 | } | ||
163 | if (s_semid != -1) { | ||
164 | semctl(s_semid, 0, IPC_RMID, 0); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void ipcsyslog_init(void) | ||
169 | { | ||
170 | if (buf == NULL) { | ||
171 | if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) { | ||
172 | bb_perror_msg_and_die("shmget"); | ||
173 | } | ||
174 | |||
175 | if ((buf = shmat(shmid, NULL, 0)) == NULL) { | ||
176 | bb_perror_msg_and_die("shmat"); | ||
177 | } | ||
178 | |||
179 | buf->size = shm_size - sizeof(*buf); | ||
180 | buf->head = buf->tail = 0; | ||
181 | |||
182 | // we'll trust the OS to set initial semval to 0 (let's hope) | ||
183 | if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1) { | ||
184 | if (errno == EEXIST) { | ||
185 | if ((s_semid = semget(KEY_ID, 2, 0)) == -1) { | ||
186 | bb_perror_msg_and_die("semget"); | ||
187 | } | ||
188 | } else { | ||
189 | bb_perror_msg_and_die("semget"); | ||
190 | } | ||
191 | } | ||
192 | } else { | ||
193 | printf("Buffer already allocated just grab the semaphore?"); | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* write message to buffer */ | ||
198 | void circ_message(const char *msg) | ||
199 | { | ||
200 | int l = strlen(msg) + 1; /* count the whole message w/ '\0' included */ | ||
201 | |||
202 | sem_down(s_semid); | ||
203 | |||
204 | /* | ||
205 | * Circular Buffer Algorithm: | ||
206 | * -------------------------- | ||
207 | * | ||
208 | * Start-off w/ empty buffer of specific size SHM_SIZ | ||
209 | * Start filling it up w/ messages. I use '\0' as separator to break up messages. | ||
210 | * This is also very handy since we can do printf on message. | ||
211 | * | ||
212 | * Once the buffer is full we need to get rid of the first message in buffer and | ||
213 | * insert the new message. (Note: if the message being added is >1 message then | ||
214 | * we will need to "remove" >1 old message from the buffer). The way this is done | ||
215 | * is the following: | ||
216 | * When we reach the end of the buffer we set a mark and start from the beginning. | ||
217 | * Now what about the beginning and end of the buffer? Well we have the "head" | ||
218 | * index/pointer which is the starting point for the messages and we have "tail" | ||
219 | * index/pointer which is the ending point for the messages. When we "display" the | ||
220 | * messages we start from the beginning and continue until we reach "tail". If we | ||
221 | * reach end of buffer, then we just start from the beginning (offset 0). "head" and | ||
222 | * "tail" are actually offsets from the beginning of the buffer. | ||
223 | * | ||
224 | * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide | ||
225 | * a threasafe way of handling shared memory operations. | ||
226 | */ | ||
227 | if ((buf->tail + l) < buf->size) { | ||
228 | /* before we append the message we need to check the HEAD so that we won't | ||
229 | overwrite any of the message that we still need and adjust HEAD to point | ||
230 | to the next message! */ | ||
231 | if (buf->tail < buf->head) { | ||
232 | if ((buf->tail + l) >= buf->head) { | ||
233 | /* we need to move the HEAD to point to the next message | ||
234 | * Theoretically we have enough room to add the whole message to the | ||
235 | * buffer, because of the first outer IF statement, so we don't have | ||
236 | * to worry about overflows here! | ||
237 | */ | ||
238 | int k = buf->tail + l - buf->head; /* we need to know how many bytes | ||
239 | we are overwriting to make | ||
240 | enough room */ | ||
241 | char *c = | ||
242 | memchr(buf->data + buf->head + k, '\0', | ||
243 | buf->size - (buf->head + k)); | ||
244 | if (c != NULL) { /* do a sanity check just in case! */ | ||
245 | buf->head = c - buf->data + 1; /* we need to convert pointer to | ||
246 | offset + skip the '\0' since | ||
247 | we need to point to the beginning | ||
248 | of the next message */ | ||
249 | /* Note: HEAD is only used to "retrieve" messages, it's not used | ||
250 | when writing messages into our buffer */ | ||
251 | } else { /* show an error message to know we messed up? */ | ||
252 | printf("Weird! Can't find the terminator token??? \n"); | ||
253 | buf->head = 0; | ||
254 | } | ||
255 | } | ||
256 | } | ||
257 | |||
258 | /* in other cases no overflows have been done yet, so we don't care! */ | ||
259 | /* we should be ok to append the message now */ | ||
260 | strncpy(buf->data + buf->tail, msg, l); /* append our message */ | ||
261 | buf->tail += l; /* count full message w/ '\0' terminating char */ | ||
262 | } else { | ||
263 | /* we need to break up the message and "circle" it around */ | ||
264 | char *c; | ||
265 | int k = buf->tail + l - buf->size; /* count # of bytes we don't fit */ | ||
266 | |||
267 | /* We need to move HEAD! This is always the case since we are going | ||
268 | * to "circle" the message. | ||
269 | */ | ||
270 | c = memchr(buf->data + k, '\0', buf->size - k); | ||
271 | |||
272 | if (c != NULL) { /* if we don't have '\0'??? weird!!! */ | ||
273 | /* move head pointer */ | ||
274 | buf->head = c - buf->data + 1; | ||
275 | |||
276 | /* now write the first part of the message */ | ||
277 | strncpy(buf->data + buf->tail, msg, l - k - 1); | ||
278 | |||
279 | /* ALWAYS terminate end of buffer w/ '\0' */ | ||
280 | buf->data[buf->size - 1] = '\0'; | ||
281 | |||
282 | /* now write out the rest of the string to the beginning of the buffer */ | ||
283 | strcpy(buf->data, &msg[l - k - 1]); | ||
284 | |||
285 | /* we need to place the TAIL at the end of the message */ | ||
286 | buf->tail = k + 1; | ||
287 | } else { | ||
288 | printf | ||
289 | ("Weird! Can't find the terminator token from the beginning??? \n"); | ||
290 | buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */ | ||
291 | } | ||
292 | |||
293 | } | ||
294 | sem_up(s_semid); | ||
295 | } | ||
296 | #endif /* CONFIG_FEATURE_IPC_SYSLOG */ | ||
297 | |||
298 | /* Note: There is also a function called "message()" in init.c */ | ||
299 | /* Print a message to the log file. */ | ||
300 | static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2))); | ||
301 | static void message(char *fmt, ...) | ||
302 | { | ||
303 | int fd; | ||
304 | struct flock fl; | ||
305 | va_list arguments; | ||
306 | |||
307 | fl.l_whence = SEEK_SET; | ||
308 | fl.l_start = 0; | ||
309 | fl.l_len = 1; | ||
310 | |||
311 | #ifdef CONFIG_FEATURE_IPC_SYSLOG | ||
312 | if ((circular_logging == TRUE) && (buf != NULL)) { | ||
313 | char b[1024]; | ||
314 | |||
315 | va_start(arguments, fmt); | ||
316 | vsnprintf(b, sizeof(b) - 1, fmt, arguments); | ||
317 | va_end(arguments); | ||
318 | circ_message(b); | ||
319 | |||
320 | } else | ||
321 | #endif | ||
322 | if ((fd = | ||
323 | device_open(logFilePath, | ||
324 | O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND | | ||
325 | O_NONBLOCK)) >= 0) { | ||
326 | fl.l_type = F_WRLCK; | ||
327 | fcntl(fd, F_SETLKW, &fl); | ||
328 | #ifdef CONFIG_FEATURE_ROTATE_LOGFILE | ||
329 | if ( logFileSize > 0 ) { | ||
330 | struct stat statf; | ||
331 | int r = fstat(fd, &statf); | ||
332 | if( !r && (statf.st_mode & S_IFREG) | ||
333 | && (lseek(fd,0,SEEK_END) > logFileSize) ) { | ||
334 | if(logFileRotate > 0) { | ||
335 | int i; | ||
336 | char oldFile[(strlen(logFilePath)+3)], newFile[(strlen(logFilePath)+3)]; | ||
337 | for(i=logFileRotate-1;i>0;i--) { | ||
338 | sprintf(oldFile, "%s.%d", logFilePath, i-1); | ||
339 | sprintf(newFile, "%s.%d", logFilePath, i); | ||
340 | rename(oldFile, newFile); | ||
341 | } | ||
342 | sprintf(newFile, "%s.%d", logFilePath, 0); | ||
343 | fl.l_type = F_UNLCK; | ||
344 | fcntl (fd, F_SETLKW, &fl); | ||
345 | close(fd); | ||
346 | rename(logFilePath, newFile); | ||
347 | fd = device_open (logFilePath, | ||
348 | O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND | | ||
349 | O_NONBLOCK); | ||
350 | fl.l_type = F_WRLCK; | ||
351 | fcntl (fd, F_SETLKW, &fl); | ||
352 | } else { | ||
353 | ftruncate( fd, 0 ); | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | #endif | ||
358 | va_start(arguments, fmt); | ||
359 | vdprintf(fd, fmt, arguments); | ||
360 | va_end(arguments); | ||
361 | fl.l_type = F_UNLCK; | ||
362 | fcntl(fd, F_SETLKW, &fl); | ||
363 | close(fd); | ||
364 | } else { | ||
365 | /* Always send console messages to /dev/console so people will see them. */ | ||
366 | if ((fd = | ||
367 | device_open(_PATH_CONSOLE, | ||
368 | O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) { | ||
369 | va_start(arguments, fmt); | ||
370 | vdprintf(fd, fmt, arguments); | ||
371 | va_end(arguments); | ||
372 | close(fd); | ||
373 | } else { | ||
374 | fprintf(stderr, "Bummer, can't print: "); | ||
375 | va_start(arguments, fmt); | ||
376 | vfprintf(stderr, fmt, arguments); | ||
377 | fflush(stderr); | ||
378 | va_end(arguments); | ||
379 | } | ||
380 | } | ||
381 | } | ||
382 | |||
383 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
384 | static void init_RemoteLog(void) | ||
385 | { | ||
386 | memset(&remoteaddr, 0, sizeof(remoteaddr)); | ||
387 | remotefd = socket(AF_INET, SOCK_DGRAM, 0); | ||
388 | |||
389 | if (remotefd < 0) { | ||
390 | bb_error_msg("cannot create socket"); | ||
391 | } | ||
392 | |||
393 | remoteaddr.sin_family = AF_INET; | ||
394 | remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list; | ||
395 | remoteaddr.sin_port = htons(RemotePort); | ||
396 | } | ||
397 | #endif | ||
398 | |||
399 | static void logMessage(int pri, char *msg) | ||
400 | { | ||
401 | time_t now; | ||
402 | char *timestamp; | ||
403 | static char res[20] = ""; | ||
404 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
405 | static char line[MAXLINE + 1]; | ||
406 | #endif | ||
407 | CODE *c_pri, *c_fac; | ||
408 | |||
409 | if (pri != 0) { | ||
410 | for (c_fac = facilitynames; | ||
411 | c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++); | ||
412 | for (c_pri = prioritynames; | ||
413 | c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++); | ||
414 | if (c_fac->c_name == NULL || c_pri->c_name == NULL) { | ||
415 | snprintf(res, sizeof(res), "<%d>", pri); | ||
416 | } else { | ||
417 | snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || | ||
422 | msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') { | ||
423 | time(&now); | ||
424 | timestamp = ctime(&now) + 4; | ||
425 | timestamp[15] = '\0'; | ||
426 | } else { | ||
427 | timestamp = msg; | ||
428 | timestamp[15] = '\0'; | ||
429 | msg += 16; | ||
430 | } | ||
431 | |||
432 | /* todo: supress duplicates */ | ||
433 | |||
434 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
435 | if (doRemoteLog == TRUE) { | ||
436 | /* trying connect the socket */ | ||
437 | if (-1 == remotefd) { | ||
438 | init_RemoteLog(); | ||
439 | } | ||
440 | |||
441 | /* if we have a valid socket, send the message */ | ||
442 | if (-1 != remotefd) { | ||
443 | now = 1; | ||
444 | snprintf(line, sizeof(line), "<%d> %s", pri, msg); | ||
445 | |||
446 | retry: | ||
447 | /* send message to remote logger */ | ||
448 | if(( -1 == sendto(remotefd, line, strlen(line), 0, | ||
449 | (struct sockaddr *) &remoteaddr, | ||
450 | sizeof(remoteaddr))) && (errno == EINTR)) { | ||
451 | /* sleep now seconds and retry (with now * 2) */ | ||
452 | sleep(now); | ||
453 | now *= 2; | ||
454 | goto retry; | ||
455 | } | ||
456 | } | ||
457 | } | ||
458 | |||
459 | if (local_logging == TRUE) | ||
460 | #endif | ||
461 | { | ||
462 | /* now spew out the message to wherever it is supposed to go */ | ||
463 | if (small) | ||
464 | message("%s %s\n", timestamp, msg); | ||
465 | else | ||
466 | message("%s %s %s %s\n", timestamp, LocalHostName, res, msg); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | static void quit_signal(int sig) | ||
471 | { | ||
472 | logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting."); | ||
473 | unlink(lfile); | ||
474 | #ifdef CONFIG_FEATURE_IPC_SYSLOG | ||
475 | ipcsyslog_cleanup(); | ||
476 | #endif | ||
477 | |||
478 | exit(TRUE); | ||
479 | } | ||
480 | |||
481 | static void domark(int sig) | ||
482 | { | ||
483 | if (MarkInterval > 0) { | ||
484 | logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --"); | ||
485 | alarm(MarkInterval); | ||
486 | } | ||
487 | } | ||
488 | |||
489 | /* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are | ||
490 | * enabled, we otherwise get a "storage size isn't constant error. */ | ||
491 | static int serveConnection(char *tmpbuf, int n_read) | ||
492 | { | ||
493 | char *p = tmpbuf; | ||
494 | |||
495 | while (p < tmpbuf + n_read) { | ||
496 | |||
497 | int pri = (LOG_USER | LOG_NOTICE); | ||
498 | int num_lt = 0; | ||
499 | char line[MAXLINE + 1]; | ||
500 | unsigned char c; | ||
501 | char *q = line; | ||
502 | |||
503 | while ((c = *p) && q < &line[sizeof(line) - 1]) { | ||
504 | if (c == '<' && num_lt == 0) { | ||
505 | /* Parse the magic priority number. */ | ||
506 | num_lt++; | ||
507 | pri = 0; | ||
508 | while (isdigit(*(++p))) { | ||
509 | pri = 10 * pri + (*p - '0'); | ||
510 | } | ||
511 | if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) { | ||
512 | pri = (LOG_USER | LOG_NOTICE); | ||
513 | } | ||
514 | } else if (c == '\n') { | ||
515 | *q++ = ' '; | ||
516 | } else if (iscntrl(c) && (c < 0177)) { | ||
517 | *q++ = '^'; | ||
518 | *q++ = c ^ 0100; | ||
519 | } else { | ||
520 | *q++ = c; | ||
521 | } | ||
522 | p++; | ||
523 | } | ||
524 | *q = '\0'; | ||
525 | p++; | ||
526 | /* Now log it */ | ||
527 | logMessage(pri, line); | ||
528 | } | ||
529 | return n_read; | ||
530 | } | ||
531 | |||
532 | static void doSyslogd(void) __attribute__ ((noreturn)); | ||
533 | static void doSyslogd(void) | ||
534 | { | ||
535 | struct sockaddr_un sunx; | ||
536 | socklen_t addrLength; | ||
537 | |||
538 | int sock_fd; | ||
539 | fd_set fds; | ||
540 | |||
541 | /* Set up signal handlers. */ | ||
542 | signal(SIGINT, quit_signal); | ||
543 | signal(SIGTERM, quit_signal); | ||
544 | signal(SIGQUIT, quit_signal); | ||
545 | signal(SIGHUP, SIG_IGN); | ||
546 | signal(SIGCHLD, SIG_IGN); | ||
547 | #ifdef SIGCLD | ||
548 | signal(SIGCLD, SIG_IGN); | ||
549 | #endif | ||
550 | signal(SIGALRM, domark); | ||
551 | alarm(MarkInterval); | ||
552 | |||
553 | /* Create the syslog file so realpath() can work. */ | ||
554 | if (realpath(_PATH_LOG, lfile) != NULL) { | ||
555 | unlink(lfile); | ||
556 | } | ||
557 | |||
558 | memset(&sunx, 0, sizeof(sunx)); | ||
559 | sunx.sun_family = AF_UNIX; | ||
560 | strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path)); | ||
561 | if ((sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { | ||
562 | bb_perror_msg_and_die("Couldn't get file descriptor for socket " | ||
563 | _PATH_LOG); | ||
564 | } | ||
565 | |||
566 | addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path); | ||
567 | if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) { | ||
568 | bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG); | ||
569 | } | ||
570 | |||
571 | if (chmod(lfile, 0666) < 0) { | ||
572 | bb_perror_msg_and_die("Could not set permission on " _PATH_LOG); | ||
573 | } | ||
574 | #ifdef CONFIG_FEATURE_IPC_SYSLOG | ||
575 | if (circular_logging == TRUE) { | ||
576 | ipcsyslog_init(); | ||
577 | } | ||
578 | #endif | ||
579 | |||
580 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
581 | if (doRemoteLog == TRUE) { | ||
582 | init_RemoteLog(); | ||
583 | } | ||
584 | #endif | ||
585 | |||
586 | logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER); | ||
587 | |||
588 | for (;;) { | ||
589 | |||
590 | FD_ZERO(&fds); | ||
591 | FD_SET(sock_fd, &fds); | ||
592 | |||
593 | if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) { | ||
594 | if (errno == EINTR) { | ||
595 | /* alarm may have happened. */ | ||
596 | continue; | ||
597 | } | ||
598 | bb_perror_msg_and_die("select error"); | ||
599 | } | ||
600 | |||
601 | if (FD_ISSET(sock_fd, &fds)) { | ||
602 | int i; | ||
603 | |||
604 | RESERVE_CONFIG_BUFFER(tmpbuf, MAXLINE + 1); | ||
605 | |||
606 | memset(tmpbuf, '\0', MAXLINE + 1); | ||
607 | if ((i = recv(sock_fd, tmpbuf, MAXLINE, 0)) > 0) { | ||
608 | serveConnection(tmpbuf, i); | ||
609 | } else { | ||
610 | bb_perror_msg_and_die("UNIX socket error"); | ||
611 | } | ||
612 | RELEASE_CONFIG_BUFFER(tmpbuf); | ||
613 | } /* FD_ISSET() */ | ||
614 | } /* for main loop */ | ||
615 | } | ||
616 | |||
617 | extern int syslogd_main(int argc, char **argv) | ||
618 | { | ||
619 | int opt; | ||
620 | |||
621 | int doFork = TRUE; | ||
622 | |||
623 | char *p; | ||
624 | |||
625 | /* do normal option parsing */ | ||
626 | while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) { | ||
627 | switch (opt) { | ||
628 | case 'm': | ||
629 | MarkInterval = atoi(optarg) * 60; | ||
630 | break; | ||
631 | case 'n': | ||
632 | doFork = FALSE; | ||
633 | break; | ||
634 | case 'O': | ||
635 | logFilePath = optarg; | ||
636 | break; | ||
637 | #ifdef CONFIG_FEATURE_ROTATE_LOGFILE | ||
638 | case 's': | ||
639 | logFileSize = atoi(optarg) * 1024; | ||
640 | break; | ||
641 | case 'b': | ||
642 | logFileRotate = atoi(optarg); | ||
643 | if( logFileRotate > 99 ) logFileRotate = 99; | ||
644 | break; | ||
645 | #endif | ||
646 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
647 | case 'R': | ||
648 | RemoteHost = bb_xstrdup(optarg); | ||
649 | if ((p = strchr(RemoteHost, ':'))) { | ||
650 | RemotePort = atoi(p + 1); | ||
651 | *p = '\0'; | ||
652 | } | ||
653 | doRemoteLog = TRUE; | ||
654 | break; | ||
655 | case 'L': | ||
656 | local_logging = TRUE; | ||
657 | break; | ||
658 | #endif | ||
659 | #ifdef CONFIG_FEATURE_IPC_SYSLOG | ||
660 | case 'C': | ||
661 | if (optarg) { | ||
662 | int buf_size = atoi(optarg); | ||
663 | if (buf_size >= 4) { | ||
664 | shm_size = buf_size * 1024; | ||
665 | } | ||
666 | } | ||
667 | circular_logging = TRUE; | ||
668 | break; | ||
669 | #endif | ||
670 | case 'S': | ||
671 | small = true; | ||
672 | break; | ||
673 | default: | ||
674 | bb_show_usage(); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
679 | /* If they have not specified remote logging, then log locally */ | ||
680 | if (doRemoteLog == FALSE) | ||
681 | local_logging = TRUE; | ||
682 | #endif | ||
683 | |||
684 | |||
685 | /* Store away localhost's name before the fork */ | ||
686 | gethostname(LocalHostName, sizeof(LocalHostName)); | ||
687 | if ((p = strchr(LocalHostName, '.'))) { | ||
688 | *p = '\0'; | ||
689 | } | ||
690 | |||
691 | umask(0); | ||
692 | |||
693 | if (doFork == TRUE) { | ||
694 | #if defined(__uClinux__) | ||
695 | vfork_daemon_rexec(0, 1, argc, argv, "-n"); | ||
696 | #else /* __uClinux__ */ | ||
697 | if(daemon(0, 1) < 0) | ||
698 | bb_perror_msg_and_die("daemon"); | ||
699 | #endif /* __uClinux__ */ | ||
700 | } | ||
701 | doSyslogd(); | ||
702 | |||
703 | return EXIT_SUCCESS; | ||
704 | } | ||
705 | |||
706 | /* | ||
707 | Local Variables | ||
708 | c-file-style: "linux" | ||
709 | c-basic-offset: 4 | ||
710 | tab-width: 4 | ||
711 | End: | ||
712 | */ | ||