]>
Commit | Line | Data |
---|---|---|
35111b89 JR |
1 | /* minilogd.c |
2 | * | |
3 | * A pale imitation of syslogd. Most notably, doesn't write anything | |
4 | * anywhere except possibly back to syslogd. | |
5 | * | |
6 | * Copyright (c) 1999-2001 Red Hat, Inc. All rights reserved. | |
7 | * | |
8 | * This software may be freely redistributed under the terms of the GNU | |
9 | * public license. | |
10 | * | |
11 | * You should have received a copy of the GNU General Public License | |
12 | * along with this program; if not, write to the Free Software | |
13 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
14 | * | |
15 | */ | |
16 | ||
17 | #include <errno.h> | |
18 | #include <fcntl.h> | |
19 | #include <signal.h> | |
20 | #include <stdio.h> | |
21 | #include <stdlib.h> | |
22 | #include <syslog.h> | |
23 | #include <unistd.h> | |
24 | ||
25 | #include <sys/poll.h> | |
26 | #include <sys/socket.h> | |
27 | #include <sys/stat.h> | |
28 | #include <sys/un.h> | |
29 | ||
30 | static int we_own_log=0; | |
31 | static char **buffer=NULL; | |
32 | static int buflines=0; | |
33 | ||
34 | int debug; | |
35 | ||
36 | int recvsock; | |
37 | ||
38 | void alarm_handler(int x) { | |
39 | alarm(0); | |
40 | close(recvsock); | |
41 | recvsock = -1; | |
42 | } | |
43 | ||
44 | void freeBuffer() { | |
45 | struct sockaddr_un addr; | |
46 | int sock; | |
47 | int x=0,conn; | |
48 | ||
49 | bzero(&addr,sizeof(addr)); | |
50 | addr.sun_family = AF_LOCAL; | |
51 | strncpy(addr.sun_path,_PATH_LOG,sizeof(addr.sun_path)-1); | |
52 | /* wait for klogd to hit syslog */ | |
53 | sleep(2); | |
54 | sock = socket(AF_LOCAL, SOCK_DGRAM,0); | |
55 | conn=connect(sock,(struct sockaddr *) &addr,sizeof(addr)); | |
56 | while (x<buflines) { | |
57 | if (!conn) write(sock,buffer[x],strlen(buffer[x])+1); | |
58 | free(buffer[x]); | |
59 | x++; | |
60 | } | |
61 | } | |
62 | ||
63 | void cleanup(int exitcode) { | |
64 | /* If we own the log, unlink it before trying to free our buffer. | |
65 | * Otherwise, sending the buffer to /dev/log doesn't make much sense.... */ | |
66 | if (we_own_log) { | |
67 | perror("wol"); | |
68 | unlink(_PATH_LOG); | |
69 | } | |
70 | /* Don't try to free buffer if we were called from a signal handler */ | |
71 | if (exitcode<=0) { | |
72 | if (buffer) freeBuffer(); | |
73 | exit(exitcode); | |
74 | } else | |
75 | exit(exitcode+128); | |
76 | } | |
77 | ||
78 | void runDaemon(int sock) { | |
79 | struct sockaddr_un addr; | |
9628cdf1 ER |
80 | int x,len,done=0; |
81 | int addrlen = sizeof(struct sockaddr_un); | |
35111b89 JR |
82 | char *message; |
83 | struct stat s1,s2; | |
84 | struct pollfd pfds; | |
85 | ||
86 | daemon(0,-1); | |
87 | /* try not to leave stale sockets lying around */ | |
88 | /* Hopefully, we won't actually get any of these */ | |
89 | signal(SIGHUP,cleanup); | |
90 | signal(SIGINT,cleanup); | |
91 | signal(SIGQUIT,cleanup); | |
92 | signal(SIGILL,cleanup); | |
93 | signal(SIGABRT,cleanup); | |
94 | signal(SIGFPE,cleanup); | |
95 | signal(SIGSEGV,cleanup); | |
96 | signal(SIGPIPE,cleanup); | |
97 | signal(SIGBUS,cleanup); | |
98 | signal(SIGTERM,cleanup); | |
99 | done = 0; | |
100 | /* Get stat info on /dev/log so we can later check to make sure we | |
101 | * still own it... */ | |
102 | if (stat(_PATH_LOG,&s1) != 0) | |
103 | memset(&s1, '\0', sizeof(struct stat)); | |
104 | while (!done) { | |
105 | pfds.fd = sock; | |
106 | pfds.events = POLLIN|POLLPRI; | |
107 | if ( ( (x=poll(&pfds,1,500))==-1) && errno !=EINTR) { | |
108 | perror("poll"); | |
109 | cleanup(-1); | |
110 | } | |
111 | if ( (x>0) && pfds.revents & (POLLIN | POLLPRI)) { | |
112 | message = calloc(8192,sizeof(char)); | |
9628cdf1 | 113 | addrlen = sizeof(struct sockaddr_un); |
35111b89 | 114 | recvsock = accept(sock,(struct sockaddr *) &addr, &addrlen); |
9628cdf1 ER |
115 | if (recvsock == -1) |
116 | continue; | |
35111b89 JR |
117 | alarm(2); |
118 | signal(SIGALRM, alarm_handler); | |
9628cdf1 | 119 | len = recv(recvsock,message,8192,0); |
35111b89 JR |
120 | alarm(0); |
121 | close(recvsock); | |
122 | if (len>0) { | |
123 | if (buflines < 200000) { | |
124 | if (buffer) | |
125 | buffer = realloc(buffer,(buflines+1)*sizeof(char *)); | |
126 | else | |
127 | buffer = malloc(sizeof(char *)); | |
128 | message[strlen(message)]='\n'; | |
129 | buffer[buflines]=message; | |
130 | buflines++; | |
131 | } | |
132 | } | |
133 | else { | |
134 | recvsock=-1; | |
135 | } | |
136 | } | |
137 | if ( (x>0) && ( pfds.revents & (POLLHUP | POLLNVAL)) ) | |
138 | done = 1; | |
139 | /* Check to see if syslogd's yanked our socket out from under us */ | |
140 | if ( (stat(_PATH_LOG,&s2)!=0) || | |
141 | (s1.st_ino != s2.st_ino ) || (s1.st_ctime != s2.st_ctime) || | |
9628cdf1 | 142 | (s1.st_mtime != s2.st_mtime) ) { |
35111b89 JR |
143 | done = 1; |
144 | we_own_log = 0; | |
145 | } | |
146 | } | |
147 | cleanup(0); | |
148 | } | |
149 | ||
150 | int main(int argc, char **argv) { | |
151 | struct sockaddr_un addr; | |
152 | int sock; | |
153 | int pid; | |
154 | ||
155 | /* option processing made simple... */ | |
156 | if (argc>1) debug=1; | |
157 | /* just in case */ | |
158 | sock = open("/dev/null",O_RDWR); | |
159 | dup2(sock,0); | |
160 | dup2(sock,1); | |
161 | dup2(sock,2); | |
162 | close(sock); | |
163 | ||
164 | bzero(&addr, sizeof(addr)); | |
165 | addr.sun_family = AF_LOCAL; | |
166 | strncpy(addr.sun_path,_PATH_LOG,sizeof(addr.sun_path)-1); | |
167 | sock = socket(AF_LOCAL, SOCK_STREAM,0); | |
168 | unlink(_PATH_LOG); | |
169 | /* Bind socket before forking, so we know if the server started */ | |
170 | if (!bind(sock,(struct sockaddr *) &addr, sizeof(addr))) { | |
171 | we_own_log = 1; | |
172 | listen(sock,5); | |
173 | if ((pid=fork())==-1) { | |
174 | perror("fork"); | |
175 | exit(3); | |
176 | } | |
177 | if (pid) { | |
178 | exit(0); | |
179 | } else { | |
180 | runDaemon(sock); | |
181 | /* shouldn't get back here... */ | |
182 | exit(4); | |
183 | } | |
184 | } else { | |
185 | exit(5); | |
186 | } | |
187 | } |