
/* splogger-nosyslog.c
 * Author: Eric Lammerts <eric@scintilla.utwente.nl>, August 1997
 * Loosely based on splogger.c that comes with qmail
 * $Id: splogger-nosyslog.c,v 1.2 1997/08/06 15:58:09 eric Exp eric $
 */

#include<errno.h>
#include<fcntl.h>
#include<pwd.h>
#include<time.h>
#include<signal.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<sys/time.h>
#include<syslog.h>

char buf[800];
int bufpos = 0;
int flagcont = 0;
char stamp[40];
int fd = 0;
int interrupted;
int outofsync = 0;
char *file;

void do_sync(int sig)
{
  if(outofsync) fdatasync(fd);
  outofsync = 0;
  signal(SIGALRM,do_sync);
  alarm(15);
}

void do_reopen(int sig)
{
  if(fd > 0) close(fd);
  if((fd=open(file,O_CREAT|O_APPEND|O_WRONLY,0644)) < 0) {
    syslog(LOG_ERR,"can't open or create logfile %s. exiting.");
    exit(1);
  }
  syslog(LOG_INFO,"(re)opened logfile %s",file);
  signal(SIGHUP,do_reopen);
}  

void do_quit(int sig)
{
  syslog(LOG_INFO,"exiting on SIGPIPE");
  exit(0);
}

void flush()
{
  time_t t;
  int stamplen;
  
  t = time(0);
  if (bufpos) {
    buf[bufpos++] = '\n';
    buf[bufpos] = 0;
    stamplen = strftime(stamp,39,"%b %d %H:%M:%S",localtime(&t));
    stamp[stamplen++] = flagcont? '+':' ';
    write(fd,stamp,stamplen);
    write(fd,buf,bufpos);
    outofsync = 1;
    flagcont = 1;
  }
  bufpos = 0;
}

void main(int argc, char **argv)
{
  char ch;
  struct passwd *pw;

  openlog("splogger-nosyslog",LOG_PID,LOG_LOCAL1);
  if(geteuid() == 0 && getuid() != 0) {
     if((pw = getpwnam("qmaill")) == NULL || pw->pw_uid != getuid()) {
       syslog(LOG_ERR,"setuid root splogger-nosyslog invoked with uid != qmaill. exiting.");
       exit(1);
     }
  }
  if(argc < 2) {
    syslog(LOG_ERR,"usage: splogger-nosyslog logfile. exiting.");
    exit(1);
  }
  syslog(LOG_INFO,"starting (uid=%d, euid=%d)",getuid(),geteuid());
  umask(002);
  file = argv[1];
  signal(SIGPIPE,do_quit);
  do_reopen(0);
  do_sync(0);
  for (;;) {
    interrupted = 0;
    switch(read(0,&ch,1)) {
      case -1:
        if(errno == EINTR) continue;
      case 0:
        if(interrupted) continue;
        syslog(LOG_INFO,"exiting");
        exit(0);
    }
    if (ch == '\n') { flush(); flagcont = 0; continue; }
    if (bufpos == sizeof(buf) - 1) flush();
    if ((ch < 32) || (ch > 126)) ch = '?';
    buf[bufpos++] = ch;
  }
}
