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"
33 static int do_logger(const char *name
, int facility
, FILE *f
)
54 perror("chdir(\"/\")");
58 while (fgets(buf
, sizeof(buf
), f
))
60 if ((p
=strchr(buf
, '\n')) != 0) *p
=0;
62 while ((c
=getchar()) != EOF
&& c
!= '\n')
66 fprintf(stderr
, "%s: %s\n", name
, buf
);
69 if (strncmp(buf
, "ERR:", 4) == 0)
74 else if (strncmp(buf
, "WARN:", 5) == 0)
79 else if (strncmp(buf
, "ALERT:", 6) == 0)
84 else if (strncmp(buf
, "CRIT:", 5) == 0)
89 else if (strncmp(buf
, "DEBUG:", 6) == 0)
94 else if (strncmp(buf
, "INFO:", 5) == 0)
107 static const char *namearg
=0;
108 static const char *pidarg
=0;
109 static char *lockfilename
=0;
117 static struct lognames facilitynames
[] =
120 { "auth", LOG_AUTH
},
123 { "authpriv", LOG_AUTHPRIV
},
126 { "console", LOG_CONSOLE
},
129 { "cron", LOG_CRON
},
132 { "daemon", LOG_DAEMON
},
138 { "kern", LOG_KERN
},
144 { "mail", LOG_MAIL
},
147 { "news", LOG_NEWS
},
150 { "security", LOG_SECURITY
},
153 { "user", LOG_USER
},
156 { "uucp", LOG_UUCP
},
159 { "local0", LOG_LOCAL0
},
162 { "local1", LOG_LOCAL1
},
165 { "local2", LOG_LOCAL2
},
168 { "local3", LOG_LOCAL3
},
171 { "local4", LOG_LOCAL4
},
174 { "local5", LOG_LOCAL5
},
177 { "local6", LOG_LOCAL6
},
180 { "local7", LOG_LOCAL7
},
185 static int hup_restart
= 0;
186 static int respawn
= 0;
187 static int child_pid
= -1;
189 static RETSIGTYPE
sighup(int n
)
193 /* The child may respond to HUP by dying. If so it will
194 close its stderr and do_logger will terminate; at that
195 point we need to restart it */
197 kill (child_pid
, SIGHUP
);
199 signal(SIGHUP
, sighup
);
200 #if RETSIGTYPE != void
205 static RETSIGTYPE
sigalrm(int n
)
207 if (child_pid
> 0) kill(child_pid
, SIGKILL
);
208 #if RETSIGTYPE != void
213 static RETSIGTYPE
sigterm(int n
)
219 kill(child_pid
, SIGTERM
);
220 signal(SIGALRM
, sigalrm
); /* kill after 8 secs */
224 #if RETSIGTYPE != void
229 static void checkfd(int actual
, int exp
)
231 if (actual
== exp
) return;
232 fprintf(stderr
, "Bad fd, got %d, expected %d\n", actual
, exp
);
233 if (actual
< 0) perror("error");
237 static int isid(const char *p
)
241 if (*p
< '0' || *p
> '9') return (0);
247 static void setuidgid(const char *userarg
,
248 const char *grouparg
)
257 else if ((gr
=getgrnam(grouparg
)) == 0)
259 fprintf(stderr
, "Group not found: %s\n", grouparg
);
264 libmail_changegroup(gid
);
274 libmail_changeuidgid(uid
, getgid());
278 gid_t g
=getgid(), *gp
=0;
280 if (grouparg
) gp
= &g
;
281 libmail_changeusername(userarg
, gp
);
287 static void startchild(char **argv
, const char *userarg
, const char *grouparg
)
293 signal(SIGTERM
, sigterm
);
294 signal(SIGHUP
, sighup
);
296 /* Make sure the pipefds are at least 3 and 4. If we have an open
297 stderr then keep it around for debugging purposes. */
299 checkfd(open("/dev/null", O_RDWR
), 0);
302 if ((tmp
= dup(0)) > 2) close(tmp
);
304 if (pipe(pipefd
) < 0)
320 checkfd(dup(pipefd
[1]), 2);
322 setuidgid(userarg
, grouparg
);
323 execvp(argv
[0], argv
);
328 // We can close stderr now
336 checkfd(dup(pipefd
[0]), 0);
341 * Note that we now support several modes of operation:
343 * (1) standalone logger, just collect messages on stdin and feed to syslog
345 * courierlogger -name=foo
347 * (2) run a child process, collect its stderr messages and feed to syslog
348 * courierlogger [-name=foo] foo arg1 arg2
350 * (3) start a detached daemon with a child process
351 * courierlogger [-name=foo] -pid=/var/run/foo.pid -start foo arg1 arg2
353 * (4) stop or restart a detached daemon
354 * courierlogger -pid=/var/run/foo.pid -stop (or receive a SIGTERM)
355 * courierlogger -pid=/var/run/foo.pid -restart (or receive a SIGHUP)
358 int main(int argc
, char **argv
)
360 int facility
= LOG_DEST
;
363 const char *userarg
= 0;
364 const char *grouparg
= 0;
367 if (argc
== 2 && argv
[1][0] != '-')
369 /* backwards-compatibility mode */
372 checkfd(open("/dev/null", O_WRONLY
), 1);
373 checkfd(open("/dev/null", O_WRONLY
), 2);
374 do_logger(argv
[1], facility
, stdin
);
382 "Usage: courierlogger [-name=name] [-pid=pidfile] [-facility=type]\n"
383 " [-start|-stop|-restart] [cmd [args...]]\n"
389 while (argc
> 0 && argv
[0][0]=='-')
391 if (strncmp(argv
[0],"-pid=",5) == 0 && argv
[0][5])
394 lockfilename
=malloc(strlen(pidarg
)+sizeof(".lock"));
400 strcat(strcpy(lockfilename
, pidarg
), ".lock");
403 if (strncmp(argv
[0],"-name=",6) == 0 && argv
[0][6])
405 else if (strncmp(argv
[0],"-user=",6) == 0)
407 else if (strncmp(argv
[0],"-group=",7) == 0)
409 else if (strcmp(argv
[0], "-droproot") == 0)
412 if (strncmp(argv
[0],"-facility=",10) == 0)
414 struct lognames
*p
= facilitynames
;
416 while (p
->name
&& strcmp(p
->name
, &argv
[0][10]))
420 fprintf(stderr
, "Unknown facility name '%s'\n",
427 if (strcmp(argv
[0],"-start") == 0)
430 if (strcmp(argv
[0],"-stop") == 0)
433 if (strcmp(argv
[0],"-restart") == 0)
436 if (strcmp(argv
[0],"-respawn") == 0)
440 fprintf(stderr
, "Unknown option '%s'\n", argv
[0]);
446 if (daemon
&& !pidarg
)
448 fprintf(stderr
, "-pid argument required\n");
452 if (!daemon
&& pidarg
)
453 daemon
= 1; /* -start implied */
455 if (!namearg
&& daemon
!= 2 && daemon
!= 3)
457 /* choose a default name based on the program we're running */
458 if (argc
<= 0 || !argv
[0] || !argv
[0][0])
460 fprintf(stderr
, "-name option required for standalone logger\n");
463 namearg
= strrchr(argv
[0],'/');
464 namearg
= namearg
? namearg
+1 : argv
[0];
470 if (argc
<= 0 || !argv
[0] || !argv
[0][0])
472 fprintf(stderr
, "-start must be followed by a command to execute\n");
475 lockfd
=ll_daemon_start(lockfilename
);
478 perror("ll_daemon_start");
481 startchild(argv
, droproot
? userarg
:NULL
,
482 droproot
? grouparg
:NULL
);
483 ll_daemon_started(pidarg
, lockfd
);
486 exit(ll_daemon_stop(lockfilename
, pidarg
));
487 case 3: /* restart */
488 exit(ll_daemon_restart(lockfilename
, pidarg
));
489 default: /* run in foreground, with or without a child process */
492 startchild(argv
, droproot
? userarg
:NULL
,
493 droproot
? grouparg
:NULL
);
496 setuidgid(userarg
, grouparg
);
502 FILE *f
= fdopen(0, "r");
504 do_logger(namearg
, facility
, f
);
506 if (child_pid
< 0) break;
507 while ((p2
=wait(&waitstat
)) != child_pid
&&
508 (p2
!= -1 || errno
!= ECHILD
))
516 startchild(argv
, NULL
, NULL
);