2 ** Copyright 1998 - 2006 Double Precision, Inc.
3 ** See COPYING for distribution information.
12 #include <sys/types.h>
28 #include "../liblock/config.h"
29 #include "../liblock/liblock.h"
30 #include "../numlib/numlib.h"
32 static const char rcsid
[]="$Id: logger.c,v 1.11 2006/06/01 10:47:33 mrsam Exp $";
34 static int do_logger(const char *name
, int facility
, FILE *f
)
55 perror("chdir(\"/\")");
59 while (fgets(buf
, sizeof(buf
), f
))
61 if ((p
=strchr(buf
, '\n')) != 0) *p
=0;
63 while ((c
=getchar()) != EOF
&& c
!= '\n')
67 fprintf(stderr
, "%s: %s\n", name
, buf
);
70 if (strncmp(buf
, "ERR:", 4) == 0)
75 else if (strncmp(buf
, "WARN:", 5) == 0)
80 else if (strncmp(buf
, "ALERT:", 6) == 0)
85 else if (strncmp(buf
, "CRIT:", 5) == 0)
90 else if (strncmp(buf
, "DEBUG:", 6) == 0)
95 else if (strncmp(buf
, "INFO:", 5) == 0)
108 static const char *namearg
=0;
109 static const char *pidarg
=0;
110 static char *lockfilename
=0;
118 static struct lognames facilitynames
[] =
121 { "auth", LOG_AUTH
},
124 { "authpriv", LOG_AUTHPRIV
},
127 { "console", LOG_CONSOLE
},
130 { "cron", LOG_CRON
},
133 { "daemon", LOG_DAEMON
},
139 { "kern", LOG_KERN
},
145 { "mail", LOG_MAIL
},
148 { "news", LOG_NEWS
},
151 { "security", LOG_SECURITY
},
154 { "user", LOG_USER
},
157 { "uucp", LOG_UUCP
},
160 { "local0", LOG_LOCAL0
},
163 { "local1", LOG_LOCAL1
},
166 { "local2", LOG_LOCAL2
},
169 { "local3", LOG_LOCAL3
},
172 { "local4", LOG_LOCAL4
},
175 { "local5", LOG_LOCAL5
},
178 { "local6", LOG_LOCAL6
},
181 { "local7", LOG_LOCAL7
},
186 static int hup_restart
= 0;
187 static int respawn
= 0;
188 static int child_pid
= -1;
190 static RETSIGTYPE
sighup(int n
)
194 /* The child may respond to HUP by dying. If so it will
195 close its stderr and do_logger will terminate; at that
196 point we need to restart it */
198 kill (child_pid
, SIGHUP
);
200 signal(SIGHUP
, sighup
);
201 #if RETSIGTYPE != void
206 static RETSIGTYPE
sigalrm(int n
)
208 if (child_pid
> 0) kill(child_pid
, SIGKILL
);
209 #if RETSIGTYPE != void
214 static RETSIGTYPE
sigterm(int n
)
220 kill(child_pid
, SIGTERM
);
221 signal(SIGALRM
, sigalrm
); /* kill after 8 secs */
225 #if RETSIGTYPE != void
230 static void checkfd(int actual
, int exp
)
232 if (actual
== exp
) return;
233 fprintf(stderr
, "Bad fd, got %d, expected %d\n", actual
, exp
);
234 if (actual
< 0) perror("error");
238 static int isid(const char *p
)
242 if (*p
< '0' || *p
> '9') return (0);
248 static void setuidgid(const char *userarg
,
249 const char *grouparg
)
258 else if ((gr
=getgrnam(grouparg
)) == 0)
260 fprintf(stderr
, "Group not found: %s\n", grouparg
);
265 libmail_changegroup(gid
);
275 libmail_changeuidgid(uid
, getgid());
279 gid_t g
=getgid(), *gp
=0;
281 if (grouparg
) gp
= &g
;
282 libmail_changeusername(userarg
, gp
);
288 static void startchild(char **argv
, const char *userarg
, const char *grouparg
)
294 signal(SIGTERM
, sigterm
);
295 signal(SIGHUP
, sighup
);
297 /* Make sure the pipefds are at least 3 and 4. If we have an open
298 stderr then keep it around for debugging purposes. */
300 checkfd(open("/dev/null", O_RDWR
), 0);
303 if ((tmp
= dup(0)) > 2) close(tmp
);
305 if (pipe(pipefd
) < 0)
321 checkfd(dup(pipefd
[1]), 2);
323 setuidgid(userarg
, grouparg
);
324 execvp(argv
[0], argv
);
329 // We can close stderr now
337 checkfd(dup(pipefd
[0]), 0);
342 * Note that we now support several modes of operation:
344 * (1) standalone logger, just collect messages on stdin and feed to syslog
346 * courierlogger -name=foo
348 * (2) run a child process, collect its stderr messages and feed to syslog
349 * courierlogger [-name=foo] foo arg1 arg2
351 * (3) start a detached daemon with a child process
352 * courierlogger [-name=foo] -pid=/var/run/foo.pid -start foo arg1 arg2
354 * (4) stop or restart a detached daemon
355 * courierlogger -pid=/var/run/foo.pid -stop (or receive a SIGTERM)
356 * courierlogger -pid=/var/run/foo.pid -restart (or receive a SIGHUP)
359 int main(int argc
, char **argv
)
361 int facility
= LOG_DEST
;
364 const char *userarg
= 0;
365 const char *grouparg
= 0;
368 if (argc
== 2 && argv
[1][0] != '-')
370 /* backwards-compatibility mode */
373 checkfd(open("/dev/null", O_WRONLY
), 1);
374 checkfd(open("/dev/null", O_WRONLY
), 2);
375 do_logger(argv
[1], facility
, stdin
);
383 "Usage: courierlogger [-name=name] [-pid=pidfile] [-facility=type]\n"
384 " [-start|-stop|-restart] [cmd [args...]]\n"
390 while (argc
> 0 && argv
[0][0]=='-')
392 if (strncmp(argv
[0],"-pid=",5) == 0 && argv
[0][5])
395 lockfilename
=malloc(strlen(pidarg
)+sizeof(".lock"));
401 strcat(strcpy(lockfilename
, pidarg
), ".lock");
404 if (strncmp(argv
[0],"-name=",6) == 0 && argv
[0][6])
406 else if (strncmp(argv
[0],"-user=",6) == 0)
408 else if (strncmp(argv
[0],"-group=",7) == 0)
410 else if (strcmp(argv
[0], "-droproot") == 0)
413 if (strncmp(argv
[0],"-facility=",10) == 0)
415 struct lognames
*p
= facilitynames
;
417 while (p
->name
&& strcmp(p
->name
, &argv
[0][10]))
421 fprintf(stderr
, "Unknown facility name '%s'\n",
428 if (strcmp(argv
[0],"-start") == 0)
431 if (strcmp(argv
[0],"-stop") == 0)
434 if (strcmp(argv
[0],"-restart") == 0)
437 if (strcmp(argv
[0],"-respawn") == 0)
441 fprintf(stderr
, "Unknown option '%s'\n", argv
[0]);
447 if (daemon
&& !pidarg
)
449 fprintf(stderr
, "-pid argument required\n");
453 if (!daemon
&& pidarg
)
454 daemon
= 1; /* -start implied */
456 if (!namearg
&& daemon
!= 2 && daemon
!= 3)
458 /* choose a default name based on the program we're running */
459 if (argc
<= 0 || !argv
[0] || !argv
[0][0])
461 fprintf(stderr
, "-name option required for standalone logger\n");
464 namearg
= strrchr(argv
[0],'/');
465 namearg
= namearg
? namearg
+1 : argv
[0];
471 if (argc
<= 0 || !argv
[0] || !argv
[0][0])
473 fprintf(stderr
, "-start must be followed by a command to execute\n");
476 lockfd
=ll_daemon_start(lockfilename
);
479 perror("ll_daemon_start");
482 startchild(argv
, droproot
? userarg
:NULL
,
483 droproot
? grouparg
:NULL
);
484 ll_daemon_started(pidarg
, lockfd
);
487 exit(ll_daemon_stop(lockfilename
, pidarg
));
488 case 3: /* restart */
489 exit(ll_daemon_restart(lockfilename
, pidarg
));
490 default: /* run in foreground, with or without a child process */
493 startchild(argv
, droproot
? userarg
:NULL
,
494 droproot
? grouparg
:NULL
);
497 setuidgid(userarg
, grouparg
);
503 FILE *f
= fdopen(0, "r");
505 do_logger(namearg
, facility
, f
);
507 if (child_pid
< 0) break;
508 while ((p2
=wait(&waitstat
)) != child_pid
&&
509 (p2
!= -1 || errno
!= ECHILD
))
517 startchild(argv
, NULL
, NULL
);