]>
Commit | Line | Data |
---|---|---|
cee18a41 AM |
1 | |
2 | #include <errno.h> | |
3 | #include <fcntl.h> | |
4 | #include <libintl.h> | |
5 | #include <locale.h> | |
6 | #include <stdio.h> | |
7 | #include <stdlib.h> | |
8 | #include <string.h> | |
9 | #include <unistd.h> | |
10 | ||
11 | #define SYSLOG_NAMES | |
12 | #include <syslog.h> | |
13 | ||
14 | #include <sys/stat.h> | |
15 | #include <sys/wait.h> | |
16 | ||
17 | #define _(String) gettext((String)) | |
18 | ||
19 | #include <popt.h> | |
20 | ||
21 | #include "initlog.h" | |
22 | #include "process.h" | |
23 | ||
24 | static int logfacility=LOG_LOCAL7; | |
25 | static int logpriority=LOG_NOTICE; | |
26 | static int reexec=0; | |
27 | static int quiet=0; | |
28 | int debug=0; | |
29 | ||
30 | static int logEntries = 0; | |
31 | struct logInfo *logData = NULL; | |
32 | ||
33 | char *getLine(char **data) { | |
34 | /* Get one line from data */ | |
35 | char *x, *y; | |
36 | ||
37 | if (!*data) return NULL; | |
38 | ||
39 | for (x = *data; *x && (*x != '\n'); x++); | |
40 | if (*x) { | |
41 | x++; | |
42 | } else { | |
43 | if (x-*data) { | |
44 | y=malloc(x-*data+1); | |
45 | y[x-*data] = 0; | |
46 | y[x-*data-1] = '\n'; | |
47 | memcpy(y,*data,x-*data); | |
48 | } else { | |
49 | y=NULL; | |
50 | } | |
51 | *data = NULL; | |
52 | return y; | |
53 | } | |
54 | y = malloc(x-*data); | |
55 | y[x-*data-1] = 0; | |
56 | memcpy(y,*data,x-*data-1); | |
57 | *data = x; | |
58 | return y; | |
59 | } | |
60 | ||
61 | char **toArray(char *line, int *num) { | |
62 | /* Converts a long string into an array of lines. */ | |
63 | char **lines; | |
64 | char *tmpline; | |
65 | ||
66 | *num = 0; | |
67 | lines = NULL; | |
68 | ||
69 | while ((tmpline=getLine(&line))) { | |
70 | if (!*num) | |
71 | lines = (char **) malloc(sizeof(char *)); | |
72 | else | |
73 | lines = (char **) realloc(lines, (*num+1)*sizeof(char *)); | |
74 | lines[*num] = tmpline; | |
75 | (*num)++; | |
76 | } | |
77 | return lines; | |
78 | } | |
79 | ||
80 | int startDaemon() { | |
81 | int pid; | |
82 | int rc; | |
83 | ||
84 | if ( (pid = fork()) == -1 ) { | |
85 | perror("fork"); | |
86 | return -1; | |
87 | } | |
88 | if ( pid ) { | |
89 | /* parent */ | |
90 | waitpid(pid,&rc,0); | |
91 | if (WIFEXITED(rc)) { | |
92 | DDEBUG("minilogd returned %d!\n",WEXITSTATUS(rc)); | |
93 | return WEXITSTATUS(rc); | |
94 | } | |
95 | else | |
96 | return -1; | |
97 | } else { | |
98 | int fd; | |
99 | ||
100 | fd=open("/dev/null",O_RDWR); | |
101 | dup2(fd,0); | |
102 | dup2(fd,1); | |
103 | dup2(fd,2); | |
104 | /* kid */ | |
105 | execlp("minilogd","minilogd",NULL); | |
106 | perror("exec"); | |
107 | exit(-1); | |
108 | } | |
109 | } | |
110 | ||
111 | int logLine(struct logInfo *logEnt) { | |
112 | /* Logs a line... somewhere. */ | |
113 | int x=0,y=0,z=0; | |
114 | struct stat statbuf; | |
115 | ||
116 | /* Don't log empty or null lines */ | |
117 | if (!logEnt->line || !strcmp(logEnt->line,"\n")) return 0; | |
118 | ||
119 | if ( ((stat(_PATH_LOG,&statbuf)==-1) ||(access("/",W_OK)==-1)) | |
120 | && startDaemon() | |
121 | ) { | |
122 | DDEBUG("starting daemon failed, pooling entry %d\n",logEntries); | |
123 | logData=realloc(logData,(logEntries+1)*sizeof(struct logInfo)); | |
124 | logData[logEntries]= (*logEnt); | |
125 | logEntries++; | |
126 | } else { | |
127 | if (logEntries>0) { | |
128 | for (x=0;x<logEntries;x++) { | |
129 | DDEBUG("flushing log entry %d =%s=\n",x,logData[x].line); | |
130 | openlog(logData[x].cmd,0,logData[x].fac); | |
131 | syslog(logData[x].pri,"%s",logData[x].line); | |
132 | closelog(); | |
133 | } | |
134 | free(logData); | |
135 | logEntries = 0; | |
136 | } | |
137 | DDEBUG("logging =%s= via syslog\n",logEnt->line); | |
138 | openlog(logEnt->cmd,0,logEnt->fac); | |
139 | syslog(logEnt->pri,"%s",logEnt->line); | |
140 | closelog(); | |
141 | } | |
142 | return 0; | |
143 | } | |
144 | ||
145 | int logEvent(char *cmd, int eventtype,char *string) { | |
146 | char *eventtable [] = { | |
147 | _("%s babbles incoherently"), | |
148 | _("%s succeeded"), | |
149 | _("%s failed"), | |
150 | _("%s cancelled at user request"), | |
151 | _("%s failed due to a failed dependency"), | |
152 | /* insert more here */ | |
153 | NULL | |
154 | }; | |
155 | int x=0,len; | |
156 | struct logInfo logentry; | |
157 | ||
158 | if (cmd) { | |
159 | logentry.cmd = strdup(basename(cmd)); | |
160 | if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') && ( 30 <= logentry.cmd[1] <= 39 ) | |
161 | && ( 30 <= logentry.cmd[2] <= 39 ) ) | |
162 | logentry.cmd+=3; | |
163 | } else | |
164 | logentry.cmd = strdup(_("(none)")); | |
165 | if (!string) | |
166 | string = strdup(cmd); | |
167 | ||
168 | while (eventtable[x] && x<eventtype) x++; | |
169 | if (!(eventtable[x])) x=0; | |
170 | ||
171 | len=strlen(eventtable[x])+strlen(string); | |
172 | logentry.line=malloc(len); | |
173 | snprintf(logentry.line,len,eventtable[x],string); | |
174 | ||
175 | logentry.pri = logpriority; | |
176 | logentry.fac = logfacility; | |
177 | ||
178 | return logLine(&logentry); | |
179 | } | |
180 | ||
181 | int logString(char *cmd, char *string) { | |
182 | struct logInfo logentry; | |
183 | ||
184 | if (cmd) { | |
185 | logentry.cmd = strdup(basename(cmd)); | |
186 | if ((logentry.cmd[0] =='K' || logentry.cmd[0] == 'S') && ( 30 <= logentry.cmd[1] <= 39 ) | |
187 | && ( 30 <= logentry.cmd[2] <= 39 ) ) | |
188 | logentry.cmd+=3; | |
189 | } else | |
190 | logentry.cmd = strdup(_("")); | |
191 | logentry.line = strdup(string); | |
192 | logentry.pri = logpriority; | |
193 | logentry.fac = logfacility; | |
194 | ||
195 | return logLine(&logentry); | |
196 | } | |
197 | ||
198 | int processArgs(int argc, char **argv, int silent) { | |
199 | char *cmdname=NULL; | |
200 | int cmdevent=0; | |
201 | char *cmd=NULL; | |
202 | char *logstring=NULL; | |
203 | char *fac=NULL,*pri=NULL; | |
204 | poptContext context; | |
205 | int rc; | |
206 | struct poptOption optTable[] = { | |
207 | POPT_AUTOHELP | |
208 | { "name", 'n', POPT_ARG_STRING, &cmdname, 0, | |
209 | "name of service being logged", NULL | |
210 | }, | |
211 | { "event", 'e', POPT_ARG_INT, &cmdevent, 0, | |
212 | "event being logged (see man page)", NULL | |
213 | }, | |
214 | { "cmd", 'c', POPT_ARG_STRING, &cmd, 0, | |
215 | "command to run, logging output", NULL | |
216 | }, | |
217 | { "debug", 'd', POPT_ARG_NONE, &debug, 0, | |
218 | "print lots of verbose debugging info", NULL | |
219 | }, | |
220 | { "run", 'r', POPT_ARG_STRING, &cmd, 3, | |
221 | "command to run, accepting input on open fd", NULL | |
222 | }, | |
223 | { "string", 's', POPT_ARG_STRING, &logstring, 0, | |
224 | "string to log", NULL | |
225 | }, | |
226 | { "facility", 'f', POPT_ARG_STRING, &fac, 1, | |
227 | "facility to log at (default: 'daemon')", NULL | |
228 | }, | |
229 | { "priority", 'p', POPT_ARG_STRING, &pri, 2, | |
230 | "priority to log at (default: 'notice')", NULL | |
231 | }, | |
232 | { "quiet", 'q', POPT_ARG_NONE, &quiet, 0, | |
233 | "suppress stdout/stderr", NULL | |
234 | }, | |
235 | { 0, 0, 0, 0, 0, 0 } | |
236 | }; | |
237 | ||
238 | context = poptGetContext("initlog", argc, argv, optTable, 0); | |
239 | ||
240 | while ((rc = poptGetNextOpt(context)) > 0) { | |
241 | switch (rc) { | |
242 | case 1: | |
243 | logfacility=atoi(fac); | |
244 | if ((logfacility == 0) && strcmp(fac,"0")) { | |
245 | int x =0; | |
246 | ||
247 | logfacility = LOG_DAEMON; | |
248 | for (x=0;facilitynames[x].c_name;x++) { | |
249 | if (!strcmp(fac,facilitynames[x].c_name)) { | |
250 | logfacility = facilitynames[x].c_val; | |
251 | break; | |
252 | } | |
253 | } | |
254 | } | |
255 | break; | |
256 | case 2: | |
257 | logpriority = atoi(pri); | |
258 | if ((logpriority == 0) && strcmp(pri,"0")) { | |
259 | int x=0; | |
260 | ||
261 | logpriority = LOG_NOTICE; | |
262 | for (x=0;prioritynames[x].c_name;x++) { | |
263 | if (!strcmp(pri,prioritynames[x].c_name)) { | |
264 | logpriority = prioritynames[x].c_val; | |
265 | break; | |
266 | } | |
267 | } | |
268 | } | |
269 | break; | |
270 | case 3: | |
271 | reexec = 1; | |
272 | break; | |
273 | default: | |
274 | break; | |
275 | } | |
276 | } | |
277 | ||
278 | if ((rc < -1)) { | |
279 | if (!silent) | |
280 | fprintf(stderr, "%s: %s\n", | |
281 | poptBadOption(context, POPT_BADOPTION_NOALIAS), | |
282 | poptStrerror(rc)); | |
283 | ||
284 | return -1; | |
285 | } | |
286 | if ( (cmd && logstring) || (cmd && cmdname) ) { | |
287 | if (!silent) | |
288 | fprintf(stderr, _("--cmd and --run are incompatible with --string or --name\n")); | |
289 | return -1; | |
290 | } | |
291 | if ( cmdname && (!logstring && !cmdevent)) { | |
292 | if (!silent) | |
293 | fprintf(stderr, _("--name requires one of --event or --string\n")); | |
294 | return -1; | |
295 | } | |
296 | if (cmdevent) { | |
297 | logEvent(cmdname,cmdevent,logstring); | |
298 | } else if (logstring) { | |
299 | logString(cmdname,logstring); | |
300 | } else if ( cmd ) { | |
301 | return(runCommand(cmd,reexec,quiet,debug)); | |
302 | } else { | |
303 | if (!silent) | |
304 | fprintf(stderr,"nothing to do!\n"); | |
305 | return -1; | |
306 | } | |
307 | return 0; | |
308 | } | |
309 | ||
310 | int main(int argc, char **argv) { | |
311 | ||
312 | setlocale(LC_ALL,""); | |
313 | bindtextdomain("initlog","/etc/locale"); | |
314 | textdomain("initlog"); | |
315 | exit(processArgs(argc,argv,0)); | |
316 | } |