]> git.pld-linux.org Git - projects/rc-scripts.git/blob - src/initlog.c
8a6d868df77f9234dbe9b2bfcc9da96611e8a43e
[projects/rc-scripts.git] / src / initlog.c
1 /* $Id: initlog.c,v 1.3 1999/12/15 18:41:08 misiek Exp $ */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <libintl.h>
6 #include <locale.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11
12 #define SYSLOG_NAMES
13 #include <syslog.h>
14
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17
18 #define _(String) gettext((String))
19
20 #include <popt.h>
21
22 #include <regex.h>
23
24 #include "initlog.h"
25 #include "process.h"
26
27 static int logfacility=LOG_DAEMON;
28 static int logpriority=LOG_NOTICE;
29 static int reexec=0;
30 static int quiet=0;
31 int debug=0;
32
33 regex_t  **regList = NULL;
34
35 static int logEntries = 0;
36 struct logInfo *logData = NULL;
37
38 void readConfiguration(char *fname) {
39     int fd,num=0;
40     struct stat sbuf;
41     char *data,*line;
42     regex_t *regexp;
43     int lfac=-1,lpri=-1;
44     
45     if ((fd=open(fname,O_RDONLY))==-1) return;
46     if (fstat(fd,&sbuf)) {
47             close(fd);
48             return;
49     }
50     data=malloc(sbuf.st_size+1);
51     if (read(fd,data,sbuf.st_size)!=sbuf.st_size) {
52             close(fd);
53             return;
54     }
55     close(fd);
56     data[sbuf.st_size] = '\0';
57     while ((line=getLine(&data))) {
58         if (line[0]=='#') continue;
59         if (!strncmp(line,"ignore ",7)) {
60             regexp = malloc(sizeof(regex_t));
61             if (!regcomp(regexp,line+7,REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) {
62                 regList = realloc(regList,(num+2) * sizeof(regex_t *));
63                 regList[num] = regexp;
64                 regList[num+1] = NULL;
65                 num++;
66             }
67         }
68         if (!strncmp(line,"facility ",9)) {
69             lfac=atoi(line+9);
70             if ((lfac == 0) && strcmp(line+9,"0")) {
71                 int x =0;
72                 
73                 lfac = LOG_DAEMON;
74                 for (x=0;facilitynames[x].c_name;x++) {
75                     if (!strcmp(line+9,facilitynames[x].c_name)) {
76                         lfac = facilitynames[x].c_val;
77                         break;
78                     }
79                 }
80             }
81         }
82         if (!strncmp(line,"priority ",9)) {
83             lpri = atoi(line+9);
84             if ((lpri == 0) && strcmp(line+9,"0")) {
85                 int x=0;
86                 
87                 lpri = LOG_NOTICE;
88                 for (x=0;prioritynames[x].c_name;x++) {
89                     if (!strcmp(line+9,prioritynames[x].c_name)) {
90                         lpri = prioritynames[x].c_val;
91                         break;
92                     }
93                 }
94             }
95         }
96     }
97     if (lfac!=-1) logfacility=lfac;
98     if (lpri!=-1) logpriority=lpri;
99 }
100     
101 char *getLine(char **data) {
102     /* Get one line from data */
103     /* Anything up to a carraige return (\r) or a backspace (\b) is discarded. */
104     /* If this really bothers you, mail me and I might make it configurable. */
105     /* It's here to avoid confilcts with fsck's progress bar. */
106     char *x, *y;
107     
108     if (!*data) return NULL;
109     x=*data;
110     while (*x && (*x != '\n')) {
111         while (*x && (*x != '\n') && (*x != '\r') && (*x != '\b')) x++;
112         if (*x && (*x=='\r' || *x =='\b')) {
113                 *data = x+1;
114                 x++;
115         }
116     }
117     if (*x) {
118         x++;
119     } else {
120         if (x-*data) {
121             y=malloc(x-*data+1);
122             y[x-*data] = 0;
123             y[x-*data-1] = '\n';
124             memcpy(y,*data,x-*data);
125         } else {
126             y=NULL;
127         }
128         *data = NULL;
129         return y;
130     }
131     y = malloc(x-*data);
132     y[x-*data-1] = 0;
133     memcpy(y,*data,x-*data-1);
134     *data = x;
135     return y;
136 }
137
138 char **toArray(char *line, int *num) {
139     /* Converts a long string into an array of lines. */
140     char **lines;
141     char *tmpline;
142     
143     *num = 0;
144     lines = NULL;
145     
146     while ((tmpline=getLine(&line))) {
147         if (!*num)
148           lines = (char **) malloc(sizeof(char *));
149         else
150           lines = (char **) realloc(lines, (*num+1)*sizeof(char *));
151         lines[*num] = tmpline;
152         (*num)++;
153     }
154     return lines;
155 }
156
157 int startDaemon() {
158     int pid;
159     int rc;
160     
161     if ( (pid = fork()) == -1 ) {
162         perror("fork");
163         return -1;
164     }
165     if ( pid ) {
166         /* parent */
167         waitpid(pid,&rc,0);
168         if (WIFEXITED(rc)) {
169           DDEBUG("minilogd returned %d!\n",WEXITSTATUS(rc));
170           return WEXITSTATUS(rc);
171         }
172         else
173           return -1;
174     } else {
175         int fd;
176         
177         fd=open("/dev/null",O_RDWR);
178         dup2(fd,0);
179         dup2(fd,1);
180         dup2(fd,2);
181         /* kid */
182         execlp("minilogd","minilogd",NULL);
183         perror("exec");
184         exit(-1);
185     }
186 }
187
188 int logLine(struct logInfo *logEnt) {
189     /* Logs a line... somewhere. */
190     int x;
191     struct stat statbuf;
192     
193     /* Don't log empty or null lines */
194     if (!logEnt->line || !strcmp(logEnt->line,"\n")) return 0;
195     
196     if  ( ((stat(_PATH_LOG,&statbuf)==-1) ||(access("/",W_OK)==-1))
197           && startDaemon()
198         ) {
199         DDEBUG("starting daemon failed, pooling entry %d\n",logEntries);
200         logData=realloc(logData,(logEntries+1)*sizeof(struct logInfo));
201         logData[logEntries]= (*logEnt);
202         logEntries++;
203     } else {
204         if (logEntries>0) {
205             for (x=0;x<logEntries;x++) {
206                 DDEBUG("flushing log entry %d =%s=\n",x,logData[x].line);
207                 openlog(logData[x].cmd,0,logData[x].fac);
208                 syslog(logData[x].pri,"%s",logData[x].line);
209                 closelog();
210             }
211             free(logData);
212             logEntries = 0;
213         }
214         DDEBUG("logging =%s= via syslog\n",logEnt->line);
215         openlog(logEnt->cmd,0,logEnt->fac);
216         syslog(logEnt->pri,"%s",logEnt->line);
217         closelog();
218     }
219     return 0;
220 }
221
222 int logEvent(char *cmd, int eventtype,char *string) {
223     char *eventtable [] = {
224         _("%s babbles incoherently"),
225         _("%s succeeded"),
226         _("%s failed"),
227         _("%s cancelled at user request"),
228         _("%s failed due to a failed dependency"),
229         /* insert more here */
230         NULL
231     };
232     int x=0,len;
233     struct logInfo logentry;
234     
235     if (cmd) {
236         logentry.cmd = strdup((char *)basename(cmd));
237         if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') && ( 30 <= logentry.cmd[1] <= 39 )
238             && ( 30 <= logentry.cmd[2] <= 39 ) )
239           logentry.cmd+=3;
240     } else
241       logentry.cmd = strdup(_("(none)"));
242     if (!string)
243       string = strdup(cmd);
244     
245     while (eventtable[x] && x<eventtype) x++;
246     if (!(eventtable[x])) x=0;
247     
248     len=strlen(eventtable[x])+strlen(string);
249     logentry.line=malloc(len);
250     snprintf(logentry.line,len,eventtable[x],string);
251     
252     logentry.pri = logpriority;
253     logentry.fac = logfacility;
254     
255     return logLine(&logentry);
256 }
257
258 int logString(char *cmd, char *string) {
259     struct logInfo logentry;
260     
261     if (cmd) {
262         logentry.cmd = strdup((char *)basename(cmd));
263         if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') && ( 30 <= logentry.cmd[1] <= 39 )
264             && ( 30 <= logentry.cmd[2] <= 39 ) )
265           logentry.cmd+=3;
266     } else
267       logentry.cmd = strdup(_(""));
268     logentry.line = strdup(string);
269     logentry.pri = logpriority;
270     logentry.fac = logfacility;
271     
272     return logLine(&logentry);
273 }
274
275 int processArgs(int argc, char **argv, int silent) {
276     char *cmdname=NULL;
277     char *conffile=NULL;
278     int cmdevent=0;
279     char *cmd=NULL;
280     char *logstring=NULL;
281     char *fac=NULL,*pri=NULL;
282     int lfac=-1, lpri=-1;
283     poptContext context;
284     int rc;
285     struct poptOption optTable[] = {
286         POPT_AUTOHELP
287         { "conf", 0, POPT_ARG_STRING, &conffile, 0,
288           "configuration file (default: /etc/initlog.conf)", NULL
289         },
290         { "name", 'n', POPT_ARG_STRING, &cmdname, 0,
291           "name of service being logged", NULL 
292         },
293         { "event", 'e', POPT_ARG_INT, &cmdevent, 0,
294           "event being logged (see man page)", NULL
295         },
296         { "cmd", 'c', POPT_ARG_STRING, &cmd, 0,
297           "command to run, logging output", NULL
298         },
299         { "debug", 'd', POPT_ARG_NONE, &debug, 0,
300           "print lots of verbose debugging info", NULL
301         },
302         { "run", 'r', POPT_ARG_STRING, &cmd, 3,
303           "command to run, accepting input on open fd", NULL
304         },
305         { "string", 's', POPT_ARG_STRING, &logstring, 0,
306           "string to log", NULL
307         },
308         { "facility", 'f', POPT_ARG_STRING, &fac, 1,
309           "facility to log at (default: 'local7')", NULL
310         },
311         { "priority", 'p', POPT_ARG_STRING, &pri, 2,
312           "priority to log at (default: 'notice')", NULL
313         },
314         { "quiet", 'q', POPT_ARG_NONE, &quiet, 0,
315           "suppress stdout/stderr", NULL
316         },
317         { 0, 0, 0, 0, 0, 0 }
318     };
319     
320     context = poptGetContext("initlog", argc, argv, optTable, 0);
321     
322     while ((rc = poptGetNextOpt(context)) > 0) {
323         switch (rc) {
324          case 1:
325             lfac=atoi(fac);
326             if ((lfac == 0) && strcmp(fac,"0")) {
327                 int x =0;
328                 
329                 lfac = LOG_DAEMON;
330                 for (x=0;facilitynames[x].c_name;x++) {
331                     if (!strcmp(fac,facilitynames[x].c_name)) {
332                         lfac = facilitynames[x].c_val;
333                         break;
334                     }
335                 }
336             }
337             break;
338          case 2:
339             lpri = atoi(pri);
340             if ((lpri == 0) && strcmp(pri,"0")) {
341                 int x=0;
342                 
343                 lpri = LOG_NOTICE;
344                 for (x=0;prioritynames[x].c_name;x++) {
345                     if (!strcmp(pri,prioritynames[x].c_name)) {
346                         lpri = prioritynames[x].c_val;
347                         break;
348                     }
349                 }
350             }
351             break;
352          case 3:
353             reexec = 1;
354             break;
355          default:
356             break;
357         }
358     }
359       
360     if ((rc < -1)) {
361        if (!silent)
362          fprintf(stderr, "%s: %s\n",
363                 poptBadOption(context, POPT_BADOPTION_NOALIAS),
364                 poptStrerror(rc));
365        
366         return -1;
367     }
368     if ( (cmd && logstring) || (cmd && cmdname) ) {
369         if (!silent)
370          fprintf(stderr, _("--cmd and --run are incompatible with --string or --name\n"));
371         return -1;
372     }
373     if ( cmdname && (!logstring && !cmdevent)) {
374         if (!silent)
375          fprintf(stderr, _("--name requires one of --event or --string\n"));
376         return -1;
377     }
378     if (conffile) {
379         readConfiguration(conffile);
380     } else {
381         readConfiguration("/etc/initlog.conf");
382     }
383     if (lpri!=-1) logpriority=lpri;
384     if (lfac!=-1) logfacility=lfac;
385     if (cmdevent) {
386         logEvent(cmdname,cmdevent,logstring);
387     } else if (logstring) {
388         logString(cmdname,logstring);
389     } else if ( cmd ) {
390         return(runCommand(cmd,reexec,quiet,debug));
391     } else {
392         if (!silent)
393          fprintf(stderr,"nothing to do!\n");
394         return -1;
395     }
396    return 0;
397 }
398
399 int main(int argc, char **argv) {
400
401     setlocale(LC_ALL,"");
402     bindtextdomain("initlog","/etc/locale");
403     textdomain("initlog");
404     exit(processArgs(argc,argv,0));
405 }
This page took 0.049575 seconds and 2 git commands to generate.