source: projects/initscripts/tags/initscripts-8.91.3/src/initlog.c @ 1108

Revision 1108, 10.9 KB checked in by daisuke, 14 years ago (diff)

import initscripts-8.90.6 from internal cvs repository

Line 
1/*
2 * Copyright (c) 1999-2003 Red Hat, Inc. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
16 *
17 */
18
19#include <ctype.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <libintl.h>
23#include <locale.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <unistd.h>
28
29#define SYSLOG_NAMES
30#include <syslog.h>
31
32#include <sys/socket.h>
33#include <sys/stat.h>
34#include <sys/un.h>
35#include <sys/wait.h>
36
37#define _(String) gettext((String))
38
39#include <popt.h>
40
41#include <regex.h>
42
43#include "initlog.h"
44#include "process.h"
45
46static int logfacility=LOG_DAEMON;
47static int logpriority=LOG_NOTICE;
48static int reexec=0;
49static int quiet=0;
50int debug=0;
51
52regex_t  **regList = NULL;
53
54static int logEntries = 0;
55struct logInfo *logData = NULL;
56
57void readConfiguration(char *fname) {
58    int fd,num=0;
59    struct stat sbuf;
60    char *data,*line, *d;
61    regex_t *regexp;
62    int lfac=-1,lpri=-1;
63   
64    if ((fd=open(fname,O_RDONLY))==-1) return;
65    if (fstat(fd,&sbuf)) {
66            close(fd);
67            return;
68    }
69    d = data=malloc(sbuf.st_size+1);
70    if (read(fd,data,sbuf.st_size)!=sbuf.st_size) {
71            close(fd);
72            free(data);
73            return;
74    }
75    close(fd);
76    data[sbuf.st_size] = '\0';
77    while ((line=getLine(&data))) {
78        if (line[0]=='#') continue;
79        if (!strncmp(line,"ignore ",7)) {
80            regexp = malloc(sizeof(regex_t));
81            if (!regcomp(regexp,line+7,REG_EXTENDED|REG_NOSUB|REG_NEWLINE)) {
82                regList = realloc(regList,(num+2) * sizeof(regex_t *));
83                regList[num] = regexp;
84                regList[num+1] = NULL;
85                num++;
86            }
87        }
88        if (!strncmp(line,"facility ",9)) {
89            lfac=atoi(line+9);
90            if ((lfac == 0) && strcmp(line+9,"0")) {
91                int x =0;
92               
93                lfac = LOG_DAEMON;
94                for (x=0;facilitynames[x].c_name;x++) {
95                    if (!strcmp(line+9,facilitynames[x].c_name)) {
96                        lfac = facilitynames[x].c_val;
97                        break;
98                    }
99                }
100            }
101        }
102        if (!strncmp(line,"priority ",9)) {
103            lpri = atoi(line+9);
104            if ((lpri == 0) && strcmp(line+9,"0")) {
105                int x=0;
106               
107                lpri = LOG_NOTICE;
108                for (x=0;prioritynames[x].c_name;x++) {
109                    if (!strcmp(line+9,prioritynames[x].c_name)) {
110                        lpri = prioritynames[x].c_val;
111                        break;
112                    }
113                }
114            }
115        }
116    }
117    if (lfac!=-1) logfacility=lfac;
118    if (lpri!=-1) logpriority=lpri;
119    free(d);
120}
121   
122char *getLine(char **data) {
123    /* Get one line from data */
124    /* Anything up to a carraige return (\r) or a backspace (\b) is discarded. */
125    /* If this really bothers you, mail me and I might make it configurable. */
126    /* It's here to avoid confilcts with fsck's progress bar. */
127    char *x, *y;
128   
129    if (!*data) return NULL;
130    x=*data;
131    while (*x && (*x != '\n')) {
132        while (*x && (*x != '\n') && (*x != '\r') && (*x != '\b')) x++;
133        if (*x && (*x=='\r' || *x =='\b')) {
134                *data = x+1;
135                x++;
136        }
137    }
138    if (*x) {
139        x++;
140    } else {
141        if (x-*data) {
142            y=malloc(x-*data+1);
143            y[x-*data] = 0;
144            y[x-*data-1] = '\n';
145            memcpy(y,*data,x-*data);
146        } else {
147            y=NULL;
148        }
149        *data = NULL;
150        return y;
151    }
152    y = malloc(x-*data);
153    y[x-*data-1] = 0;
154    memcpy(y,*data,x-*data-1);
155    *data = x;
156    return y;
157}
158
159char **toArray(char *line, int *num) {
160    /* Converts a long string into an array of lines. */
161    char **lines;
162    char *tmpline;
163   
164    *num = 0;
165    lines = NULL;
166   
167    while ((tmpline=getLine(&line))) {
168        if (!*num)
169          lines = (char **) malloc(sizeof(char *));
170        else
171          lines = (char **) realloc(lines, (*num+1)*sizeof(char *));
172        lines[*num] = tmpline;
173        (*num)++;
174    }
175    return lines;
176}
177
178int trySocket() {
179        int s;
180        struct sockaddr_un addr;
181       
182        s = socket(AF_LOCAL, SOCK_DGRAM, 0);
183        if (s<0)
184          return 1;
185   
186        bzero(&addr,sizeof(addr));
187        addr.sun_family = AF_LOCAL;
188        strncpy(addr.sun_path,_PATH_LOG,sizeof(addr.sun_path)-1);
189
190        if (connect(s,(struct sockaddr *) &addr,sizeof(addr))<0) {
191                if (errno == EPROTOTYPE || errno == ECONNREFUSED) {
192                        DDEBUG("connect failed (EPROTOTYPE), trying stream\n");
193                        close(s);
194                        s = socket(AF_LOCAL, SOCK_STREAM, 0);
195                        if (connect(s,(struct sockaddr *) &addr, sizeof(addr)) < 0) {
196                                DDEBUG("connect failed: %s\n",strerror(errno));
197                                close(s);
198                                return 1;
199                        } 
200                        close(s);
201                        return 0;
202                }
203                close(s);
204                DDEBUG("connect failed: %s\n",strerror(errno));
205                return 1;
206        } else {
207                close(s);
208                return 0;
209        }
210}
211
212int logLine(struct logInfo *logEnt) {
213    /* Logs a line... somewhere. */
214    int x;
215    struct stat statbuf;
216   
217    /* Don't log empty or null lines */
218    if (!logEnt->line || !strcmp(logEnt->line,"\n")) return 0;
219   
220       
221    if  ((stat(_PATH_LOG,&statbuf)==-1) || trySocket()) {
222        DDEBUG("starting daemon failed, pooling entry %d\n",logEntries);
223        logData=realloc(logData,(logEntries+1)*sizeof(struct logInfo));
224        logData[logEntries].fac = logEnt->fac;
225        logData[logEntries].pri = logEnt->pri;
226        logData[logEntries].cmd = strdup(logEnt->cmd);
227        logData[logEntries].line = strdup(logEnt->line);
228        logEntries++;
229    } else {
230        if (logEntries>0) {
231            for (x=0;x<logEntries;x++) {
232                DDEBUG("flushing log entry %d =%s=\n",x,logData[x].line);
233                openlog(logData[x].cmd,0,logData[x].fac);
234                syslog(logData[x].pri,"%s",logData[x].line);
235                closelog();
236            }
237            free(logData);
238            logEntries = 0;
239        }
240        DDEBUG("logging =%s= via syslog\n",logEnt->line);
241        openlog(logEnt->cmd,0,logEnt->fac);
242        syslog(logEnt->pri,"%s",logEnt->line);
243        closelog();
244    }
245    return 0;
246}
247
248int logEvent(char *cmd, int eventtype,char *string) {
249    char *eventtable [] = {
250        _("%s babbles incoherently"),
251        _("%s succeeded"),
252        _("%s failed"),
253        _("%s cancelled at user request"),
254        _("%s failed due to a failed dependency"),
255        /* insert more here */
256        NULL
257    };
258    int x=0,len, rc;
259    struct logInfo logentry;
260   
261    if (cmd) {
262        logentry.cmd = basename(cmd);
263        if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') &&
264            ( logentry.cmd[1] >= '0' && logentry.cmd[1] <= '9' ) &&
265            ( logentry.cmd[2] >= '0' && logentry.cmd[2] <= '9' ) )
266          logentry.cmd+=3;
267        logentry.cmd = strdup(logentry.cmd);
268    } else
269      logentry.cmd = strdup(_("(none)"));
270    if (!string) {
271      string = alloca(strlen(cmd)+1);
272      strcpy(string,cmd);
273    }
274   
275    while (eventtable[x] && x<eventtype) x++;
276    if (!(eventtable[x])) x=0;
277   
278    len=strlen(eventtable[x])+strlen(string);
279    logentry.line=malloc(len);
280    snprintf(logentry.line,len,eventtable[x],string);
281   
282    logentry.pri = logpriority;
283    logentry.fac = logfacility;
284   
285    rc = logLine(&logentry);
286    free(logentry.line);
287    free(logentry.cmd);
288    return rc;
289}
290
291int logString(char *cmd, char *string) {
292    struct logInfo logentry;
293    int rc;
294   
295    if (cmd) {
296        logentry.cmd = basename(cmd);
297        if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') && 
298            ( logentry.cmd[1] >= '0' && logentry.cmd[1] <= 0x39 ) &&
299            ( logentry.cmd[2] >= '0' && logentry.cmd[2] <= 0x39 ) )
300          logentry.cmd+=3;
301        logentry.cmd = strdup(logentry.cmd);
302    } else
303      logentry.cmd = strdup(_(""));
304    logentry.line = strdup(string);
305    logentry.pri = logpriority;
306    logentry.fac = logfacility;
307   
308    rc = logLine(&logentry);
309    free(logentry.line);
310    free(logentry.cmd);
311    return rc;
312}
313
314int processArgs(int argc, char **argv, int silent) {
315    char *cmdname=NULL;
316    char *conffile=NULL;
317    int cmdevent=0;
318    char *cmd=NULL;
319    char *logstring=NULL;
320    char *fac=NULL,*pri=NULL;
321    int lfac=-1, lpri=-1;
322    poptContext context;
323    int rc;
324    struct poptOption optTable[] = {
325        POPT_AUTOHELP
326        { "conf", 0, POPT_ARG_STRING, &conffile, 0,
327          "configuration file (default: /etc/initlog.conf)", NULL
328        },
329        { "name", 'n', POPT_ARG_STRING, &cmdname, 0,
330          "name of service being logged", NULL 
331        },
332        { "event", 'e', POPT_ARG_INT, &cmdevent, 0,
333          "event being logged (see man page)", NULL
334        },
335        { "cmd", 'c', POPT_ARG_STRING, &cmd, 0,
336          "command to run, logging output", NULL
337        },
338        { "debug", 'd', POPT_ARG_NONE, &debug, 0,
339          "print lots of verbose debugging info", NULL
340        },
341        { "run", 'r', POPT_ARG_STRING, &cmd, 3,
342          "command to run, accepting input on open fd", NULL
343        },
344        { "string", 's', POPT_ARG_STRING, &logstring, 0,
345          "string to log", NULL
346        },
347        { "facility", 'f', POPT_ARG_STRING, &fac, 1,
348          "facility to log at (default: 'local7')", NULL
349        },
350        { "priority", 'p', POPT_ARG_STRING, &pri, 2,
351          "priority to log at (default: 'notice')", NULL
352        },
353        { "quiet", 'q', POPT_ARG_NONE, &quiet, 0,
354          "suppress stdout/stderr", NULL
355        },
356        { 0, 0, 0, 0, 0, 0 }
357    };
358   
359    context = poptGetContext("initlog", argc, argv, optTable, 0);
360   
361    while ((rc = poptGetNextOpt(context)) > 0) {
362        switch (rc) {
363         case 1:
364            lfac=atoi(fac);
365            if ((lfac == 0) && strcmp(fac,"0")) {
366                int x =0;
367               
368                lfac = LOG_DAEMON;
369                for (x=0;facilitynames[x].c_name;x++) {
370                    if (!strcmp(fac,facilitynames[x].c_name)) {
371                        lfac = facilitynames[x].c_val;
372                        break;
373                    }
374                }
375            }
376            break;
377         case 2:
378            lpri = atoi(pri);
379            if ((lpri == 0) && strcmp(pri,"0")) {
380                int x=0;
381               
382                lpri = LOG_NOTICE;
383                for (x=0;prioritynames[x].c_name;x++) {
384                    if (!strcmp(pri,prioritynames[x].c_name)) {
385                        lpri = prioritynames[x].c_val;
386                        break;
387                    }
388                }
389            }
390            break;
391         case 3:
392            reexec = 1;
393            break;
394         default:
395            break;
396        }
397    }
398     
399    if ((rc < -1)) {
400       if (!silent)
401         fprintf(stderr, "%s: %s\n",
402                poptBadOption(context, POPT_BADOPTION_NOALIAS),
403                poptStrerror(rc));
404       
405        return -1;
406    }
407    if ( (cmd && logstring) || (cmd && cmdname) ) {
408        if (!silent)
409         fprintf(stderr, _("--cmd and --run are incompatible with --string or --name\n"));
410        return -1;
411    }
412    if ( cmdname && (!logstring && !cmdevent)) {
413        if (!silent)
414         fprintf(stderr, _("--name requires one of --event or --string\n"));
415        return -1;
416    }
417    if (cmdevent && cmd) {
418            if (!silent)
419              fprintf(stderr, _("--cmd and --run are incompatible with --event\n"));
420            return -1;
421    }
422    if (conffile) {
423        readConfiguration(conffile);
424    } else {
425        readConfiguration("/etc/initlog.conf");
426    }
427    if (cmd) {
428            while (isspace(*cmd)) cmd++;
429    }
430    if (lpri!=-1) logpriority=lpri;
431    if (lfac!=-1) logfacility=lfac;
432    if (cmdevent) {
433        logEvent(cmdname,cmdevent,logstring);
434    } else if (logstring) {
435        logString(cmdname,logstring);
436    } else if ( cmd && *cmd) {
437        return(runCommand(cmd,reexec,quiet,debug));
438    } else {
439        if (!silent)
440         fprintf(stderr,"nothing to do!\n");
441        return -1;
442    }
443   return 0;
444}
445
446int main(int argc, char **argv) {
447
448    setlocale(LC_ALL,"");
449    bindtextdomain("initlog","/etc/locale");
450    textdomain("initlog");
451    fprintf(stderr, _("WARNING: initlog is deprecated and will be removed in a future release\n"));
452    exit(processArgs(argc,argv,0));
453}
Note: See TracBrowser for help on using the repository browser.