]>
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; | |
80 | int x,len,addrlen,done=0; | |
81 | char *message; | |
82 | struct stat s1,s2; | |
83 | struct pollfd pfds; | |
84 | ||
85 | daemon(0,-1); | |
86 | /* try not to leave stale sockets lying around */ | |
87 | /* Hopefully, we won't actually get any of these */ | |
88 | signal(SIGHUP,cleanup); | |
89 | signal(SIGINT,cleanup); | |
90 | signal(SIGQUIT,cleanup); | |
91 | signal(SIGILL,cleanup); | |
92 | signal(SIGABRT,cleanup); | |
93 | signal(SIGFPE,cleanup); | |
94 | signal(SIGSEGV,cleanup); | |
95 | signal(SIGPIPE,cleanup); | |
96 | signal(SIGBUS,cleanup); | |
97 | signal(SIGTERM,cleanup); | |
98 | done = 0; | |
99 | /* Get stat info on /dev/log so we can later check to make sure we | |
100 | * still own it... */ | |
101 | if (stat(_PATH_LOG,&s1) != 0) | |
102 | memset(&s1, '\0', sizeof(struct stat)); | |
103 | while (!done) { | |
104 | pfds.fd = sock; | |
105 | pfds.events = POLLIN|POLLPRI; | |
106 | if ( ( (x=poll(&pfds,1,500))==-1) && errno !=EINTR) { | |
107 | perror("poll"); | |
108 | cleanup(-1); | |
109 | } | |
110 | if ( (x>0) && pfds.revents & (POLLIN | POLLPRI)) { | |
111 | message = calloc(8192,sizeof(char)); | |
112 | recvsock = accept(sock,(struct sockaddr *) &addr, &addrlen); | |
113 | alarm(2); | |
114 | signal(SIGALRM, alarm_handler); | |
115 | len = read(recvsock,message,8192); | |
116 | alarm(0); | |
117 | close(recvsock); | |
118 | if (len>0) { | |
119 | if (buflines < 200000) { | |
120 | if (buffer) | |
121 | buffer = realloc(buffer,(buflines+1)*sizeof(char *)); | |
122 | else | |
123 | buffer = malloc(sizeof(char *)); | |
124 | message[strlen(message)]='\n'; | |
125 | buffer[buflines]=message; | |
126 | buflines++; | |
127 | } | |
128 | } | |
129 | else { | |
130 | recvsock=-1; | |
131 | } | |
132 | } | |
133 | if ( (x>0) && ( pfds.revents & (POLLHUP | POLLNVAL)) ) | |
134 | done = 1; | |
135 | /* Check to see if syslogd's yanked our socket out from under us */ | |
136 | if ( (stat(_PATH_LOG,&s2)!=0) || | |
137 | (s1.st_ino != s2.st_ino ) || (s1.st_ctime != s2.st_ctime) || | |
138 | (s1.st_mtime != s2.st_mtime) || (s1.st_atime != s2.st_atime) ) { | |
139 | done = 1; | |
140 | we_own_log = 0; | |
141 | } | |
142 | } | |
143 | cleanup(0); | |
144 | } | |
145 | ||
146 | int main(int argc, char **argv) { | |
147 | struct sockaddr_un addr; | |
148 | int sock; | |
149 | int pid; | |
150 | ||
151 | /* option processing made simple... */ | |
152 | if (argc>1) debug=1; | |
153 | /* just in case */ | |
154 | sock = open("/dev/null",O_RDWR); | |
155 | dup2(sock,0); | |
156 | dup2(sock,1); | |
157 | dup2(sock,2); | |
158 | close(sock); | |
159 | ||
160 | bzero(&addr, sizeof(addr)); | |
161 | addr.sun_family = AF_LOCAL; | |
162 | strncpy(addr.sun_path,_PATH_LOG,sizeof(addr.sun_path)-1); | |
163 | sock = socket(AF_LOCAL, SOCK_STREAM,0); | |
164 | unlink(_PATH_LOG); | |
165 | /* Bind socket before forking, so we know if the server started */ | |
166 | if (!bind(sock,(struct sockaddr *) &addr, sizeof(addr))) { | |
167 | we_own_log = 1; | |
168 | listen(sock,5); | |
169 | if ((pid=fork())==-1) { | |
170 | perror("fork"); | |
171 | exit(3); | |
172 | } | |
173 | if (pid) { | |
174 | exit(0); | |
175 | } else { | |
176 | runDaemon(sock); | |
177 | /* shouldn't get back here... */ | |
178 | exit(4); | |
179 | } | |
180 | } else { | |
181 | exit(5); | |
182 | } | |
183 | } |