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