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