]> TLD Linux GIT Repositories - rc-scripts.git/blob - src/minilogd.c
- from PLD
[rc-scripts.git] / src / minilogd.c
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,done=0;
81    int addrlen = sizeof(struct sockaddr_un);
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));
113          addrlen = sizeof(struct sockaddr_un);
114          recvsock = accept(sock,(struct sockaddr *) &addr, &addrlen);
115          if (recvsock == -1)
116                       continue;
117          alarm(2);
118          signal(SIGALRM, alarm_handler);
119          len = recv(recvsock,message,8192,0);
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) ||
142             (s1.st_mtime != s2.st_mtime) ) {
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 }